avatarAmy @GrabNGoInfo

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

22395

Abstract

umber">103.</span></pre></div><p id="47c8">After downloading the model vocabulary, the method <code>tokenizer</code> is used to tokenize the review corpus.</p><ul><li><code>max_length</code> indicates the maximum number of tokens kept for each document.</li></ul><p id="189a">👉 If the document has more tokens than the <code>max_length</code>, it will be truncated.</p><p id="6c22">👉 If the document has less tokens than the <code>max_length</code>, it will be padded with zeros.</p><p id="b422">👉 If <code>max_length</code> is unset or set to <code>None</code>, the maximum length from the pretrained model will be used. If the pretrained model does not have a maximum length parameter, <code>max_length</code> will be deactivated.</p><ul><li><code>truncation</code> controls how the token truncation is implemented. <code>truncation=True</code> indicates that the truncation length is the length specified by <code>max_length</code>. If <code>max_length</code> is not specified, the max_length of the pretrained model is used.</li><li><code>padding</code> means adding zeros to shorter reviews in the dataset. The <code>padding</code> argument controls how <code>padding</code> is conducted.</li></ul><p id="0582">👉 <code>padding=True</code> is the same as <code>padding='longest'</code>. It checks the longest sequence in the batch and pads zeros to that length. There is no padding if only one text document is provided.</p><p id="6fbd">👉 <code>padding='max_length'</code> pads to <code>max_length</code> if it is specified, otherwise, it pads to the maximum acceptable input length for the model.</p><p id="b65c">👉 <code>padding=False</code> is the same as <code>padding='do_not_pad'</code>. It is the default, indicating that no padding is applied, so it can output a batch with sequences of different lengths.</p><div id="ec4a"><pre><span class="hljs-comment"># Funtion to tokenize data</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">tokenize_dataset</span>(<span class="hljs-params">data</span>): <span class="hljs-keyword">return</span> tokenizer(data[<span class="hljs-string">"review"</span>], max_length=<span class="hljs-number">32</span>, truncation=<span class="hljs-literal">True</span>, padding=<span class="hljs-string">"max_length"</span>)

<span class="hljs-comment"># Tokenize the dataset</span> dataset_train = hg_train_data.<span class="hljs-built_in">map</span>(tokenize_dataset) dataset_test = hg_test_data.<span class="hljs-built_in">map</span>(tokenize_dataset)</pre></div><p id="a628">After tokenization, we can see that both the training and the testing Dataset have 6 features, <code>'review'</code>, <code>'label'</code>, <code>'index_level_0'</code>, <code>'input_ids'</code>, <code>'token_type_ids'</code>, and <code>'attention_mask'</code>. The number of rows is stored with <code>num_rows</code>.</p><div id="bd3f"><pre><span class="hljs-comment"># Take a look at the data</span> <span class="hljs-built_in">print</span>(dataset_train) <span class="hljs-built_in">print</span>(dataset_test)</pre></div><p id="7201">Output:</p><div id="3ac1"><pre><span class="hljs-title function_ invoke__">Dataset</span>({ <span class="hljs-attr">features</span>: [<span class="hljs-string">'review'</span>, <span class="hljs-string">'label'</span>, <span class="hljs-string">'index_level_0'</span>, <span class="hljs-string">'input_ids'</span>, <span class="hljs-string">'token_type_ids'</span>, <span class="hljs-string">'attention_mask'</span>], <span class="hljs-attr">num_rows</span>: <span class="hljs-number">800</span> }) <span class="hljs-title function_ invoke__">Dataset</span>({ <span class="hljs-attr">features</span>: [<span class="hljs-string">'review'</span>, <span class="hljs-string">'label'</span>, <span class="hljs-string">'index_level_0'</span>, <span class="hljs-string">'input_ids'</span>, <span class="hljs-string">'token_type_ids'</span>, <span class="hljs-string">'attention_mask'</span>], <span class="hljs-attr">num_rows</span>: <span class="hljs-number">200</span> })</pre></div><p id="798c">Next, some data processing is needed to make the training and testing datasets compatible with the model.</p><ul><li><code>"review"</code> and <code>"index_level_0"</code> are removed because they will not be used in the model.</li><li><code>"label"</code> is renamed to <code>"labels"</code> because the model expects the name <code>"labels"</code>.</li><li>The format of the datasets is set to PyTorch tensors.</li></ul><div id="74c3"><pre><span class="hljs-comment"># Remove the review and index columns because it will not be used in the model</span> dataset_train = dataset_train.remove_columns([<span class="hljs-string">"review"</span>, <span class="hljs-string">"index_level_0"</span>]) dataset_test = dataset_test.remove_columns([<span class="hljs-string">"review"</span>, <span class="hljs-string">"index_level_0"</span>])

<span class="hljs-comment"># Rename label to labels because the model expects the name labels</span> dataset_train = dataset_train.rename_column(<span class="hljs-string">"label"</span>, <span class="hljs-string">"labels"</span>) dataset_test = dataset_test.rename_column(<span class="hljs-string">"label"</span>, <span class="hljs-string">"labels"</span>)

<span class="hljs-comment"># Change the format to PyTorch tensors</span> dataset_train.set_format(<span class="hljs-string">"torch"</span>) dataset_test.set_format(<span class="hljs-string">"torch"</span>)

<span class="hljs-comment"># Take a look at the data</span> <span class="hljs-built_in">print</span>(dataset_train) <span class="hljs-built_in">print</span>(dataset_test)</pre></div><p id="f3dd">After the data processing, we can see that both training and testing datasets have four features.</p><div id="6041"><pre><span class="hljs-title function_ invoke__">Dataset</span>({ <span class="hljs-attr">features</span>: [<span class="hljs-string">'labels'</span>, <span class="hljs-string">'input_ids'</span>, <span class="hljs-string">'token_type_ids'</span>, <span class="hljs-string">'attention_mask'</span>], <span class="hljs-attr">num_rows</span>: <span class="hljs-number">800</span> }) <span class="hljs-title function_ invoke__">Dataset</span>({ <span class="hljs-attr">features</span>: [<span class="hljs-string">'labels'</span>, <span class="hljs-string">'input_ids'</span>, <span class="hljs-string">'token_type_ids'</span>, <span class="hljs-string">'attention_mask'</span>], <span class="hljs-attr">num_rows</span>: <span class="hljs-number">200</span> })</pre></div><p id="adca"><code>dataset_train[0]</code> gives us the content for the first record in the training dataset in a dictionary format.</p><ul><li><code>'labels'</code> is the label of the classification. The first record is a positive review, so the label is 1.</li><li><code>'input_ids'</code> are the IDs for the tokens. There are 32 token IDs because the <code>max_length</code> is 32 for the tokenization.</li><li><code>'token_type_ids'</code> is also called segment IDs.</li></ul><p id="cb04">👉 BERT was trained on two tasks, Masked Language Modeling and Next Sentence Prediction. <code>'token_type_ids'</code> is for the Next Sentence Prediction, where two sentences are used to predict whether the second sentence is the next sentence for the first one.</p><p id="41c1">👉 The first sentence has all the tokens represented by zeros, and the second sentence has all the tokens represented by ones.</p><p id="22e6">👉 Because our classification task does not have a second sentence, all the values for <code>'token_type_ids'</code> are zeros.</p><ul><li><code>'attention_mask'</code> indicates which token ID should get attention from the model, so the padding tokens are all zeros and other tokens are 1s.</li></ul><div id="d4f5"><pre><span class="hljs-comment"># Check the first record</span> dataset_train[<span class="hljs-number">0</span>]</pre></div><p id="41fb">Output:</p><div id="e18a"><pre>{<span class="hljs-attr">'labels':</span> <span class="hljs-string">tensor(1)</span>, <span class="hljs-attr">'input_ids':</span> <span class="hljs-string">tensor(</span>[ <span class="hljs-number">101</span>, <span class="hljs-number">5749</span>, <span class="hljs-number">1254</span>, <span class="hljs-number">1106</span>, <span class="hljs-number">9786</span>, <span class="hljs-number">1111</span>, <span class="hljs-number">1515</span>, <span class="hljs-number">1103</span>, <span class="hljs-number">1614</span>, <span class="hljs-number">146</span>, <span class="hljs-number">1444</span>, <span class="hljs-number">1111</span>, <span class="hljs-number">170</span>, <span class="hljs-number">1363</span>, <span class="hljs-number">3945</span>, <span class="hljs-number">106</span>, <span class="hljs-number">102</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]<span class="hljs-string">)</span>, <span class="hljs-attr">'token_type_ids':</span> <span class="hljs-string">tensor(</span>[<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]<span class="hljs-string">)</span>, <span class="hljs-attr">'attention_mask':</span> <span class="hljs-string">tensor(</span>[<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]<span class="hljs-string">)</span>}</pre></div><h1 id="4cbd">Step 6: DataLoader</h1><p id="f7f3">In step 6, we will put the training and testing datasets into <code>DataLoader</code>.</p><p id="61ab"><code>DataLoader</code> is a parallel data loading process by PyTorch. It increases the data loading speed and decreases memory usage.</p><ul><li><code>dataset</code> takes the dataset name to put in the <code>DataLoader</code>.</li><li><code>shuffle=True</code> indicates that the data will be reshuffled at every epoch. The default value is <code>False</code>. We set it <code>True</code> for the training dataset and keep the default <code>False</code> for the testing dataset.</li><li><code>batch_size=4</code> means that 4 samples will be loaded for each batch. The default value is 1.</li></ul><p id="ad59">Before putting the dataset into <code>DataLoader</code>, the unoccupied cached memory is released by <code>torch.cuda.empty_cache()</code>.</p><div id="4151"><pre><span class="hljs-comment"># Empty cache</span> torch.cuda.empty_cache()

<span class="hljs-comment"># DataLoader</span> train_dataloader = DataLoader(dataset=dataset_train, shuffle=<span class="hljs-literal">True</span>, batch_size=<span class="hljs-number">4</span>) eval_dataloader = DataLoader(dataset=dataset_test, batch_size=<span class="hljs-number">4</span>)</pre></div><h1 id="083f">Step 7: Load Pretrained Model</h1><p id="5d5f">In step 7, we will load the pretrained model for sentiment analysis.</p><ul><li><code>AutoModelForSequenceClassification</code> loads the BERT model without the sequence classification head.</li><li>The method <code>from_pretrained()</code> loads the weights from the pretrained model into the new model, so the weights in the new model are not randomly initialized. Note that the new weights for the new sequence classification head are going to be randomly initialized.</li><li><code>bert-base-cased</code> is the name of the pretrained model. We can change it to a different model based on the nature of the project.</li><li><code>num_labels</code> indicates the number of classes. Our dataset has two classes, positive and negative, so <code>num_labels=2</code>.</li></ul><div id="153c"><pre><span class="hljs-comment"># Load model</span> model = AutoModelForSequenceClassification.from_pretrained(<span class="hljs-string">"bert-base-cased"</span>, num_labels=<span class="hljs-number">2</span>)</pre></div><h1 id="2a90">Step 8: Set Learning Rate Scheduler</h1><p id="e535">In step 8, we will set up the learning rate scheduler using the <code>get_scheduler</code> method.</p><ul><li><code>name="linear"</code> indicates that the name of the scheduler is <code>linear</code>.</li><li><code>optimizer</code> takes <code>AdamW</code> as the optimizer. <code>AdamW</code> is a variation of the <code>Adam</code> optimizer. It modifies the weight decay in <code>Adam</code> by decoupling weight decay from the gradient update. <code>params</code> takes the model parameters. <code>lr</code> is the learning rate.</li><li><code>num_warmup_steps=0</code> indicates that there are no warmup steps.</li><li><code>num_training_steps</code> is the number of training steps. It is calculated as the number of epochs times the number of batches. We set the number of epochs to be 2, meaning that the model will go through the whole training dataset 2 times. The number of batches is the length of the training data loader.</li></ul><p id="3f13">Then we set the model to use GPU if it is available.</p><div id="e5db"><pre><span class="hljs-comment"># Number of epochs</span> num_epochs = <span class="hljs-number">2</span>

<span class="hljs-comment"># Number of training steps</span> num_training_steps = num_epochs * <span class="hljs-built_in">len</span>(train_dataloader)

<span class="hljs-comment"># Optimizer</span> optimizer = AdamW(params=model.parameters(), lr=<span class="hljs-number">5e-6</span>)

<span class="hljs-comment"># Set up the learning rate scheduler</span> lr_scheduler = get_scheduler(name=<span class="hljs-string">"linear"</span>, optimizer=optimizer, num_warmup_steps=<span class="hljs-number">0</span>, num_training_steps=num_training_steps)

<span class="hljs-comment"># Use GPU if it is available</span> device = torch.device(<span class="hljs-string">"cuda"</span>) <span class="hljs-keyword">if</span> torch.cuda.is_available() <span class="hljs-keyword">else</span> torch.device(<span class="hljs-string">"cpu"</span>) model.to(device)</pre></div><h1 id="04cd">Step 9: PyTorch Training Loop</h1><p id="9e6b">In step 9, we will run the PyTorch training loop for the transfer learning model.</p><p id="1cf7"><code>model.train()</code> tells the model that we are training the model. Some layers work differently for training and evaluation, and <code>model.train()</code> helps to inform the layers that the model training is in progress.</p><p id="3e32">Then the PyTorch training loop runs through each batch for each epoch.</p><ul><li>Firstly, the data is fetched from the batch and passed into the model.</li><li>Then, the output of the model is used to calculate the loss and update the weights based on backpropagation results.</li><li>After that, the learning rate scheduler is executed and the gradients are cleared.</li><li>Finally, the progress bar is updated to reflect the training progress.</li></ul><div id="64c8"><pre><span class="hljs-comment"># Set the progress bar</span> progress_bar = tqdm(<span class="hljs-built_in">range</span>(num_training_steps))

<span class="hljs-comment"># Tells the model that we are training the model</span> model.train() <span class="hljs-comment"># Loop through the epochs</span> <span class="hljs-keyword">for</span> epoch <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(num_epochs): <span class="hljs-comment"># Loop through the batches</span> <span class="hljs-keyword">for</span> batch <span class="hljs-keyword">in</span> train_dataloader: <span class="hljs-comment"># Get the batch</span> batch = {k: v.to(device) <span class="hljs-keyword">for</span> k, v <span class="hljs-keyword">in</span> batch.items()} <span class="hljs-comment"># Compute the model output for the batch</span> outputs = model(**batch) <span class="hljs-comment"># Loss computed by the model</span> loss = outputs.loss <span class="hljs-comment"># backpropagates the error to calculate gradients</span> loss.backward() <span class="hljs-comment"># Update the model weights</span> optimizer.step() <span class="hljs-comment"># Learning rate scheduler</span> lr_scheduler.step() <span class="hljs-comment"># Clear the gradients</span> optimizer.zero_grad() <span class="hljs-comment"># Update the progress bar</span> progress_bar.update(<span class="hljs-number">1</span>)</pre></div><h1 id="e4be">Step 10: PyTorch Model Prediction and Evaluation</h1><p id="da34">In step 10, we will talk about how to make model predictions and evaluations using PyTorch.</p><p id="ce71">Hugging Face has an <code>evaluate</code> library with over 100 evaluation modules. We can see the list of all the modules using <code>evaluate.list_evaluation_modules()</code>.</p><div id="60bd"><pre><span class="hljs-comment"># Number of evaluation modules</span> <span class="hljs-built_in">print</span>(<span class="hljs-string">f'There are <span class="hljs-subst">{<span class="hljs-built_in">len</span>(evaluate.list_evaluation_modules())}</span> evaluation models in Hugging Face.\n'</span>)

<span class="hljs-comment"># List all evaluation metrics</span> evaluate.list_evaluation_modules()</pre></div><p id="e61b">Output:</p><div id="a4d2"><pre><span class="hljs-type">There</span> are <span class="hljs-number">129</span> evaluation models <span class="hljs-keyword">in</span> <span class="hljs-type">Hugging</span> <span class="hljs-type">Face</span>.

[<span class="hljs-symbol">'lvwerra</span>/test', <span class="hljs-symbol">'precision'</span>, <span class="hljs-symbol">'code_eval'</span>, <span class="hljs-symbol">'roc_auc'</span>, <span class="hljs-symbol">'cuad'</span>, <span class="hljs-symbol">'xnli'</span>, <span class="hljs-symbol">'rouge'</span>, <span class="hljs-symbol">'pearsonr'</span>, <span class="hljs-symbol">'mse'</span>, <span class="hljs-symbol">'super_glue'</span>, <span class="hljs-symbol">'comet'</span>, <span class="hljs-symbol">'cer'</span>, <span class="hljs-symbol">'sacrebleu'</span>, <span class="hljs-symbol">'mahalanobis'</span>, <span class="hljs-symbol">'wer'</span>, <span class="hljs-symbol">'competition_math'</span>, <span class="hljs-symbol">'f1'</span>, <span class="hljs-symbol">'recall'</span>, <span class="hljs-symbol">'coval'</span>, <span class="hljs-symbol">'mauve'</span>, <span class="hljs-symbol">'xtreme_s'</span>, <span class="hljs-symbol">'bleurt'</span>, <span class="hljs-symbol">'ter'</span>, <span class="hljs-symbol">'accuracy'</span>, <span class="hljs-symbol">'exact_match'</span>, <span class="hljs-symbol">'indic_glue'</span>, <span class="hljs-symbol">'spearmanr'</span>, <span class="hljs-symbol">'mae'</span>, <span class="hljs-symbol">'squad'</span>, <span class="hljs-symbol">'chrf'</span>, <span class="hljs-symbol">'glue'</span>, <span class="hljs-symbol">'perplexity'</span>, <span class="hljs-symbol">'mean_iou'</span>, <span class="hljs-symbol">'squad_v2'</span>, <span class="hljs-symbol">'meteor'</span>, <span class="hljs-symbol">'bleu'</span>, <span class="hljs-symbol">'wiki_split'</span>, <span class="hljs-symbol">'sari'</span>, <span class="hljs-symbol">'frugalscore'</span>, <span class="hljs-symbol">'google_bleu'</span>, <span class="hljs-symbol">'bertscore'</span>, <span class="hljs-symbol">'matthews_correlation'</span>, <span class="hljs-symbol">'seqeval'</span>, <span class="hljs-symbol">'trec_eval'</span>, <span class="hljs-symbol">'rl_reliability'</span>, <span class="hljs-symbol">'jordyvl</span>/ece', <span class="hljs-symbol">'angelina</span>-wang/directional_bias_amplification', <span class="hljs-symbol">'cpllab</span>/syntaxgym', <sp

Options

an class="hljs-symbol">'lvwerra</span>/bary_score', <span class="hljs-symbol">'kaggle</span>/amex', <span class="hljs-symbol">'kaggle</span>/ai4code', <span class="hljs-symbol">'hack</span>/test_metric', <span class="hljs-symbol">'yzha</span>/ctc_eval', <span class="hljs-symbol">'codeparrot</span>/apps_metric', <span class="hljs-symbol">'mfumanelli</span>/geometric_mean', <span class="hljs-symbol">'daiyizheng</span>/valid', <span class="hljs-symbol">'poseval'</span>, <span class="hljs-symbol">'erntkn</span>/dice_coefficient', <span class="hljs-symbol">'mgfrantz</span>/roc_auc_macro', <span class="hljs-symbol">'Vlasta</span>/pr_auc', <span class="hljs-symbol">'gorkaartola</span>/metric_for_tp_fp_samples', <span class="hljs-symbol">'idsedykh</span>/metric', <span class="hljs-symbol">'idsedykh</span>/codebleu2', <span class="hljs-symbol">'idsedykh</span>/codebleu', <span class="hljs-symbol">'idsedykh</span>/megaglue', <span class="hljs-symbol">'kasmith</span>/woodscore', <span class="hljs-symbol">'cakiki</span>/ndcg', <span class="hljs-symbol">'brier_score'</span>, <span class="hljs-symbol">'Vertaix</span>/vendiscore', <span class="hljs-symbol">'GMFTBY</span>/dailydialogevaluate', <span class="hljs-symbol">'GMFTBY</span>/dailydialog_evaluate', <span class="hljs-symbol">'jzm</span>-mailchimp/joshs_second_test_metric', <span class="hljs-symbol">'ola13</span>/precision_at_k', <span class="hljs-symbol">'yulong</span>-me/yl_metric', <span class="hljs-symbol">'abidlabs</span>/mean_iou', <span class="hljs-symbol">'abidlabs</span>/mean_iou2', <span class="hljs-symbol">'KevinSpaghetti</span>/accuracyk', <span class="hljs-symbol">'Felipehonorato</span>/my_metric', <span class="hljs-symbol">'NimaBoscarino</span>/weat', <span class="hljs-symbol">'ronaldahmed</span>/nwentfaithfulness', <span class="hljs-symbol">'Viona</span>/infolm', <span class="hljs-symbol">'kyokote</span>/my_metric2', <span class="hljs-symbol">'kashif</span>/mape', <span class="hljs-symbol">'Ochiroo</span>/rouge_mn', <span class="hljs-symbol">'giulio98</span>/code_eval_outputs', <span class="hljs-symbol">'leslyarun</span>/fbeta_score', <span class="hljs-symbol">'giulio98</span>/codebleu', <span class="hljs-symbol">'anz2</span>/iliauniiccocrevaluation', <span class="hljs-symbol">'zbeloki</span>/m2', <span class="hljs-symbol">'xu1998hz</span>/sescore', <span class="hljs-symbol">'mase'</span>, <span class="hljs-symbol">'mape'</span>, <span class="hljs-symbol">'smape'</span>, <span class="hljs-symbol">'dvitel</span>/codebleu', <span class="hljs-symbol">'NCSOFT</span>/harim_plus', <span class="hljs-symbol">'JP</span>-<span class="hljs-type">SystemsX</span>/nDCG', <span class="hljs-symbol">'sportlosos</span>/sescore', <span class="hljs-symbol">'Drunper</span>/metrica_tesi', <span class="hljs-symbol">'jpxkqx</span>/peak_signal_to_noise_ratio', <span class="hljs-symbol">'jpxkqx</span>/signal_to_reconstrution_error', <span class="hljs-symbol">'hpi</span>-dhc/<span class="hljs-type">FairEval'</span>, <span class="hljs-symbol">'nist_mt'</span>, <span class="hljs-symbol">'lvwerra</span>/accuracy_score', <span class="hljs-symbol">'character'</span>, <span class="hljs-symbol">'charcut_mt'</span>, <span class="hljs-symbol">'ybelkada</span>/cocoevaluate', <span class="hljs-symbol">'harshhpareek</span>/bertscore', <span class="hljs-symbol">'posicube</span>/mean_reciprocal_rank', <span class="hljs-symbol">'bstrai</span>/classification_report', <span class="hljs-symbol">'omidf</span>/squad_precision_recall', <span class="hljs-symbol">'Josh98</span>/nl2bash_m', <span class="hljs-symbol">'BucketHeadP65</span>/confusion_matrix', <span class="hljs-symbol">'BucketHeadP65</span>/roc_curve', <span class="hljs-symbol">'mcnemar'</span>, <span class="hljs-symbol">'exact_match'</span>, <span class="hljs-symbol">'wilcoxon'</span>, <span class="hljs-symbol">'ncoop57</span>/levenshtein_distance', <span class="hljs-symbol">'kaleidophon</span>/almost_stochastic_order', <span class="hljs-symbol">'word_length'</span>, <span class="hljs-symbol">'lvwerra</span>/element_count', <span class="hljs-symbol">'word_count'</span>, <span class="hljs-symbol">'text_duplicates'</span>, <span class="hljs-symbol">'perplexity'</span>, <span class="hljs-symbol">'label_distribution'</span>, <span class="hljs-symbol">'toxicity'</span>, <span class="hljs-symbol">'prb977</span>/cooccurrence_count', <span class="hljs-symbol">'regard'</span>, <span class="hljs-symbol">'honest'</span>, <span class="hljs-symbol">'NimaBoscarino</span>/pseudo_perplexity']</pre></div><p id="6505">We will use three metrics to evaluate the model performance. They are <code>accuracy</code>, <code>f1</code>, and <code>recall</code>.</p><ul><li><code>accuracy</code> is the percentage of correct predictions. It ranges from 0 to 1, where 1 means perfect prediction. The higher value the accuracy is, the better the model is when the data is balanced.</li><li><code>recall</code> is also called sensitivity or true positive rate. It is the percentage of positive events captured out of all the positive events. The value for recall ranges from 0 to 1. The higher value the recall is, the better the model is.</li><li><code>f1</code> is a metric that balances precision and recall values, and it should be used when there is no clear preference between precision and recall. The F1 score ranges from 0 to 1, with the best value being 1 and the worst value being 0.</li></ul><div id="32b1"><pre><span class="hljs-comment"># Load the evaluation metric</span> metric1 = evaluate.load(<span class="hljs-string">"accuracy"</span>) metric2 = evaluate.load(<span class="hljs-string">"f1"</span>) metric3 = evaluate.load(<span class="hljs-string">"recall"</span>)</pre></div><p id="db4e">The prediction and evaluation process starts with <code>model.eval()</code>, which tells PyTorch that we are evaluating the model instead of training the model.</p><p id="2357">Because the model evaluation is processed in batches, empty lists are created to hold all the prediction results for logits, predicted probabilities, and predicted labels.</p><div id="ff6f"><pre><span class="hljs-comment"># Tells the model that we are evaluting the model performance</span> model.<span class="hljs-built_in">eval</span>()

<span class="hljs-comment"># A list for all logits</span> logits_all = []

<span class="hljs-comment"># A list for all predicted probabilities</span> predicted_prob_all = []

<span class="hljs-comment"># A list for all predicted labels</span> predictions_all = []</pre></div><p id="e556">The model predictions and evaluations are completed in the same loop for the batches. Note that since this is the prediction step, no epoch is needed.</p><ul><li>Firstly, we get the data from the batch and pass it to the model for prediction. <code>torch.no_grad()</code> is included to disable the gradient calculation. The gradient calculation is disabled for the prediction because it is only needed for the training process.</li><li>Then logits are extracted from the prediction output and appended to the list <code>logits_all</code>. Logit values from all classes do not sum up to 1.</li><li>To get the predicted probabilities, <code>torch.softmax</code> is applied on the logits. <code>dim=1</code> means that the softmax is calculated based on the rows, so for each sample, the predicted probabilities for all classes sum up to 1.</li><li>The label prediction can be based on either logits or predicted probabilities. In this example, we are using logits, but the predicted probabilities should give the same results. <code>dim=-1</code> means that the last column is the event of interest.</li><li>After having the predictions, the model performance metrics are calculated. <code>references</code> takes the true labels for the batch.</li></ul><div id="74b6"><pre><span class="hljs-comment"># Loop through the batches in the evaluation dataloader</span> <span class="hljs-keyword">for</span> batch <span class="hljs-keyword">in</span> eval_dataloader: <span class="hljs-comment"># Get the batch</span> batch = {k: v.to(device) <span class="hljs-keyword">for</span> k, v <span class="hljs-keyword">in</span> batch.items()} <span class="hljs-comment"># Disable the gradient calculation</span> <span class="hljs-keyword">with</span> torch.no_grad(): <span class="hljs-comment"># Compute the model output</span> outputs = model(**batch) <span class="hljs-comment"># Get the logits</span> logits = outputs.logits <span class="hljs-comment"># Append the logits batch to the list</span> logits_all.append(logits) <span class="hljs-comment"># Get the predicted probabilities for the batch</span> predicted_prob = torch.softmax(logits, dim=<span class="hljs-number">1</span>) <span class="hljs-comment"># Append the predicted probabilities for the batch to all the predicted probabilities</span> predicted_prob_all.append(predicted_prob) <span class="hljs-comment"># Get the predicted labels for the batch</span> predictions = torch.argmax(logits, dim=-<span class="hljs-number">1</span>) <span class="hljs-comment"># Append the predicted labels for the batch to all the predictions</span> predictions_all.append(predictions) <span class="hljs-comment"># Add the prediction batch to the evaluation metric</span> metric1.add_batch(predictions=predictions, references=batch[<span class="hljs-string">"labels"</span>]) metric2.add_batch(predictions=predictions, references=batch[<span class="hljs-string">"labels"</span>]) metric3.add_batch(predictions=predictions, references=batch[<span class="hljs-string">"labels"</span>])

<span class="hljs-comment"># Compute the metric</span> <span class="hljs-built_in">print</span>(metric1.compute()) <span class="hljs-built_in">print</span>(metric2.compute()) <span class="hljs-built_in">print</span>(metric3.compute())</pre></div><p id="10e3">The evaluation results show that the model has 0.945 accuracy, 0.943 f1 score, and 0.929 recall value.</p><div id="0817"><pre>{'accuracy': <span class="hljs-number">0.945</span>} {'f1': <span class="hljs-number">0.9430051813471502</span>} {'recall': <span class="hljs-number">0.9285714285714286</span>}</pre></div><p id="1b0b"><code>logits_all[:5]</code> gives us the first 5 batches of logits. We can see that the prediction has two columns. The first column is the predicted logit for label 0 and the second column is the predicted logit for label 1. Each batch has four samples.</p><div id="14df"><pre><span class="hljs-comment"># Take a look at the logits</span> logits_all[:<span class="hljs-number">5</span>]</pre></div><p id="1526">Output:</p><div id="0ab2"><pre>[<span class="hljs-name">tensor</span>([[<span class="hljs-name">-1.4175</span>, <span class="hljs-number">1.7728</span>], [<span class="hljs-name">-1.4442</span>, <span class="hljs-number">1.8167</span>], [<span class="hljs-name">-1.2888</span>, <span class="hljs-number">1.7954</span>], [ <span class="hljs-number">1.1902</span>, <span class="hljs-number">-1.3435</span>]], device=<span class="hljs-symbol">'cuda:0</span>'), tensor([[ <span class="hljs-number">1.0639</span>, <span class="hljs-number">-1.3628</span>], [<span class="hljs-name">-1.3469</span>, <span class="hljs-number">1.6955</span>], [ <span class="hljs-number">0.8422</span>, <span class="hljs-number">-1.3144</span>], [ <span class="hljs-number">1.1680</span>, <span class="hljs-number">-1.4845</span>]], device=<span class="hljs-symbol">'cuda:0</span>'), tensor([[<span class="hljs-name">-1.0588</span>, <span class="hljs-number">1.3745</span>], [ <span class="hljs-number">1.2833</span>, <span class="hljs-number">-1.2503</span>], [<span class="hljs-name">-1.5322</span>, <span class="hljs-number">1.5994</span>], [ <span class="hljs-number">0.1853</span>, <span class="hljs-number">-0.6757</span>]], device=<span class="hljs-symbol">'cuda:0</span>'), tensor([[<span class="hljs-name">-0.9469</span>, <span class="hljs-number">1.0366</span>], [<span class="hljs-name">-0.8427</span>, <span class="hljs-number">1.0451</span>], [<span class="hljs-name">-1.3804</span>, <span class="hljs-number">1.6149</span>], [ <span class="hljs-number">0.8212</span>, <span class="hljs-number">-1.0765</span>]], device=<span class="hljs-symbol">'cuda:0</span>'), tensor([[ <span class="hljs-number">0.9545</span>, <span class="hljs-number">-1.2628</span>], [<span class="hljs-name">-1.4912</span>, <span class="hljs-number">1.8893</span>], [<span class="hljs-name">-1.4786</span>, <span class="hljs-number">1.6621</span>], [ <span class="hljs-number">1.4001</span>, <span class="hljs-number">-1.4412</span>]], device=<span class="hljs-symbol">'cuda:0</span>')]</pre></div><p id="ff1a"><code>predicted_prob_all[:5]</code> gives the first five batches of the predicted probabilities. We can see that the sum of each row adds up to 1.</p><div id="2310"><pre><span class="hljs-comment"># Take a look at the predicted probabilities</span> predicted_prob_all[:<span class="hljs-number">5</span>]</pre></div><div id="cb47"><pre>[<span class="hljs-name">tensor</span>([[<span class="hljs-name">0.0395</span>, <span class="hljs-number">0.9605</span>], [<span class="hljs-name">0.0369</span>, <span class="hljs-number">0.9631</span>], [<span class="hljs-name">0.0438</span>, <span class="hljs-number">0.9562</span>], [<span class="hljs-name">0.9265</span>, <span class="hljs-number">0.0735</span>]], device=<span class="hljs-symbol">'cuda:0</span>'), tensor([[<span class="hljs-name">0.9188</span>, <span class="hljs-number">0.0812</span>], [<span class="hljs-name">0.0455</span>, <span class="hljs-number">0.9545</span>], [<span class="hljs-name">0.8963</span>, <span class="hljs-number">0.1037</span>], [<span class="hljs-name">0.9342</span>, <span class="hljs-number">0.0658</span>]], device=<span class="hljs-symbol">'cuda:0</span>'), tensor([[<span class="hljs-name">0.0807</span>, <span class="hljs-number">0.9193</span>], [<span class="hljs-name">0.9265</span>, <span class="hljs-number">0.0735</span>], [<span class="hljs-name">0.0418</span>, <span class="hljs-number">0.9582</span>], [<span class="hljs-name">0.7029</span>, <span class="hljs-number">0.2971</span>]], device=<span class="hljs-symbol">'cuda:0</span>'), tensor([[<span class="hljs-name">0.1209</span>, <span class="hljs-number">0.8791</span>], [<span class="hljs-name">0.1315</span>, <span class="hljs-number">0.8685</span>], [<span class="hljs-name">0.0476</span>, <span class="hljs-number">0.9524</span>], [<span class="hljs-name">0.8696</span>, <span class="hljs-number">0.1304</span>]], device=<span class="hljs-symbol">'cuda:0</span>'), tensor([[<span class="hljs-name">0.9018</span>, <span class="hljs-number">0.0982</span>], [<span class="hljs-name">0.0329</span>, <span class="hljs-number">0.9671</span>], [<span class="hljs-name">0.0415</span>, <span class="hljs-number">0.9585</span>], [<span class="hljs-name">0.9449</span>, <span class="hljs-number">0.0551</span>]], device=<span class="hljs-symbol">'cuda:0</span>')]</pre></div><p id="3608"><code>predictions_all[:5]</code> gives the first five batches of the predicted labels. We can see that the ones correspond to the higher value of logits and the zeros correspond to the lower value of the logits for each sample.</p><div id="8dd9"><pre><span class="hljs-comment"># Take a look at the predicted labels</span> predictions_all[:<span class="hljs-number">5</span>]</pre></div><p id="3f5f">Output:</p><div id="f475"><pre>[<span class="hljs-name">tensor</span>([<span class="hljs-name">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>], device=<span class="hljs-symbol">'cuda:0</span>'), tensor([<span class="hljs-name">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>], device=<span class="hljs-symbol">'cuda:0</span>'), tensor([<span class="hljs-name">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>], device=<span class="hljs-symbol">'cuda:0</span>'), tensor([<span class="hljs-name">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>], device=<span class="hljs-symbol">'cuda:0</span>'), tensor([<span class="hljs-name">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>], device=<span class="hljs-symbol">'cuda:0</span>')]</pre></div><h1 id="2a1e">Step 11: Save and Load Model</h1><p id="79e3">In step 11, we will talk about how to save the model and reload it for prediction.</p><p id="e69b"><code>tokenizer.save_pretrained</code> saves the tokenizer information to the drive and <code>model.save_model</code> saves the model to the drive.</p><div id="6434"><pre><span class="hljs-comment"># Save tokenizer</span> tokenizer.save_pretrained(<span class="hljs-string">'./sentiment_transfer_learning_pytorch/'</span>)

<span class="hljs-comment"># Save model</span> model.save_pretrained(<span class="hljs-string">'./sentiment_transfer_learning_pytorch/'</span>)</pre></div><p id="d051">We can load the saved tokenizer later using <code>AutoTokenizer.from_pretrained()</code> and load the saved model using <code>AutoModelForSequenceClassification.from_pretrained()</code>.</p><div id="186b"><pre><span class="hljs-comment"># Load tokenizer</span> tokenizer = AutoTokenizer.from_pretrained(<span class="hljs-string">"./sentiment_transfer_learning_pytorch/"</span>)

<span class="hljs-comment"># Load model</span> loaded_model = AutoModelForSequenceClassification.from_pretrained(<span class="hljs-string">'./sentiment_transfer_learning_pytorch/'</span>)</pre></div><p id="c533">More tutorials are available on GrabNGoInfo <a href="https://youtube.com/@grabngoinfo">YouTube Channel</a>, <a href="https://grabngoinfo.com/tutorials/">GrabNGoInfo.com</a>, and <a href="https://www.linkedin.com/company/grabngoinfo/">LinkedIn</a>.</p> <figure id="c685"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FUNezAbTasdE%3Flist%3DPLVppujud2yJpx5r8GFeJ81fyek8dEDMX-&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DUNezAbTasdE&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FUNezAbTasdE%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" allowfullscreen="" frameborder="0" height="480" width="854"> </div> </div> </figure></iframe></div></div></figure><h1 id="cf53">Recommended Tutorials</h1><ul><li><a href="https://readmedium.com/grabngoinfo-machine-learning-tutorials-inventory-9b9d78ebdd67">GrabNGoInfo Machine Learning Tutorials Inventory</a></li><li><a href="https://readmedium.com/transfer-learning-for-text-classification-using-hugging-face-transformers-trainer-13407187cf89">Transfer Learning for Text Classification Using Hugging Face Transformers Trainer</a></li><li><a href="https://readmedium.com/customized-sentiment-analysis-transfer-learning-using-tensorflow-with-hugging-face-1b439eedf167">Customized Sentiment Analysis: Transfer Learning Using Tensorflow with Hugging Face</a></li><li><a href="https://readmedium.com/sentiment-analysis-hugging-face-zero-shot-model-vs-flair-pre-trained-model-57047452225d">Sentiment Analysis: Hugging Face Zero-shot Model vs Flair Pre-trained Model</a></li><li><a href="https://readmedium.com/zero-shot-topic-modeling-with-deep-learning-using-python-a895d2d0c773">Zero-shot Topic Modeling with Deep Learning Using Python</a></li><li><a href="https://readmedium.com/topic-modeling-with-deep-learning-using-python-bertopic-cf91f5676504">Topic Modeling with Deep Learning Using Python BERTopic</a></li><li><a href="https://readmedium.com/google-colab-tutorial-for-beginners-834595494d44">Google Colab Tutorial for Beginners</a></li><li><a href="https://readmedium.com/textblob-vs-vader-for-sentiment-analysis-using-python-76883d40f9ae">TextBlob vs. VADER for Sentiment Analysis Using Python</a></li><li><a href="https://readmedium.com/five-ways-to-create-tables-in-databricks-cd3847cfc3aa">Five Ways To Create Tables In Databricks</a></li><li><a href="https://readmedium.com/time-series-anomaly-detection-using-prophet-in-python-877d2b7b14b4">Time Series Anomaly Detection Using Prophet in Python</a></li><li><a href="https://readmedium.com/multivariate-time-series-forecasting-with-seasonality-and-holiday-effect-using-prophet-in-python-d5d4150eeb57">Multivariate Time Series Forecasting with Seasonality and Holiday Effect Using Prophet in Python</a></li><li><a href="https://readmedium.com/time-series-causal-impact-analysis-in-python-63eacb1df5cc">Time Series Causal Impact Analysis in Python</a></li></ul><h1 id="b45d">References</h1><ul><li><a href="https://huggingface.co/docs/transformers/training">Hugging Face documentation on fine-tuning a pretrained model</a></li><li><a href="https://github.com/huggingface/notebooks/blob/main/transformers_doc/en/training.ipynb">Hugging Face notebook on fine-tuning a pretrained model</a></li><li><a href="https://huggingface.co/transformers/v3.5.1/main_classes/tokenizer.html">Hugging Face documentation on tokenizer</a></li><li><a href="https://www.youtube.com/watch?v=yofjFQddwHE">Deeplearning.AI transfer learning video from Andrew Ng</a></li><li><a href="https://github.com/huggingface/notebooks/blob/main/transformers_doc/en/training.ipynb">Hugging Face documentation on prepare_tf_dataset()</a></li><li><a href="https://huggingface.co/docs/datasets/v1.7.0/index.html#:~:text=Datasets%20and%20evaluation%20metrics%20for,Natural%20Language%20Processing%20(NLP).">Hugging Face documentation on Datasets</a></li><li><a href="https://arxiv.org/pdf/1711.05101v3.pdf">Decoupled Weight Decay Regularization paper</a></li></ul></article></body>

Transfer Learning for Text Classification Using PyTorch

Fine-tuning a pretrained transformer BERT model for customized sentiment analysis using PyTorch training loops

Photo by Igor Lepilin on Unsplash

Hugging Face provides three ways to fine-tune a pretrained text classification model: PyTorch, Tensorflow Keras, and transformer trainer. Compared with the other two ways, PyTorch training loops provide more customization and easier debugging of the training loops. This tutorial will use PyTorch to fine-tune a text classification model. We will talk about the following:

  • How does transfer learning work?
  • How to convert a pandas dataframe into a Hugging Face Dataset?
  • How to tokenize text, load a pretrained model, and train a transfer learning model using PyTorch training loops?
  • How to make predictions and evaluate the model performance of a fine-tuned transfer learning model for text classification?
  • How to save the model and re-load the model?

If you are interested in learning how to implement transfer Learning Using Tensorflow or transformer trainer, please check out my previous tutorial Customized Sentiment Analysis: Transfer Learning Using Tensorflow with Hugging Face and Transfer Learning for Text Classification Using Hugging Face Transformers Trainer.

Resources for this post:

  • Video tutorial for this post on YouTube
  • Click here for the Colab notebook
  • More video tutorials on NLP
  • More blog posts on NLP

Let’s get started!

Step 0: Transfer Learning Algorithms

In step 0, we will talk about how transfer learning works.

Transfer learning is a machine learning technique that reuses a pretrained large deep learning model on a new task. It usually includes the following steps:

  1. Select a pretrained model that is suitable for the new task. For example, if the new task includes text from different languages, a multi-language pretrained model needs to be selected.
  2. Keep all the weights and biases from the pretrained model except for the output layer. This is because the output layer for the pretrained model is for the pretrained tasks and it needs to be replaced with the new task.
  3. Feed randomly initialize weights and biases into the new head of the new task. For a sentiment analysis transfer learning (aka fine-tuning) model on a pretrained BERT model, we will remove the head that classifies mask words, and replace it with the two sentiment analysis labels, positive and negative.
  4. Retrain the model for the new task with the new data, utilizing the pretrained weights and biases. Because the weights and biases store the knowledge learned from the pretrained model, the fine-tuned transfer learning model can build on that knowledge and does not need to learn from scratch.

Step 1: Install And Import Python Libraries

In step 1, we will install and import python libraries.

Firstly, let’s install transformers, datasets, and evaluate.

# Install libraries
!pip install transformers datasets evaluate

After installing the python packages, we will import the python libraries.

  • pandas and numpy are imported for data processing.
  • torch and transformers are imported for modeling.
  • tqdm is for tracking the modeling progress.
  • Dataset is imported for the Hugging Face dataset format.
  • evaluate is imported for model performance evaluation.
# Data processing
import pandas as pd
import numpy as np

# Modeling
import torch
from torch.utils.data import DataLoader
from torch.optim import AdamW
from transformers import AutoTokenizer, AutoModelForSequenceClassification, get_scheduler

# Progress bar
from tqdm.auto import tqdm

# Hugging Face Dataset
from datasets import Dataset

# Model performance evaluation
import evaluate

Step 2: Download And Read Data

The second step is to download and read the dataset.

The UCI Machine Learning Repository has the review data from three websites: imdb.com, amazon.com, and yelp.com. We will use the review data from amazon.com for this tutorial. Please follow these steps to download the data.

  1. Go to: https://archive.ics.uci.edu/ml/datasets/Sentiment+Labelled+Sentences
  2. Click “Data Folder”
  3. Download “sentiment labeled sentences.zip”
  4. Unzip “sentiment labeled sentences.zip”
  5. Copy the file “amazon_cells_labelled.txt” to your project folder

Those who are using Google Colab for this analysis need to mount Google Drive to read the dataset. You can ignore the code below if you are not using Google Colab.

  • drive.mount is used to mount to the Google drive so the colab notebook can access the data on the Google drive.
  • os.chdir is used to change the default directory on Google drive. I set the default directory to the folder where the review dataset is saved.
  • !pwd is used to print the current working directory.

Please check out Google Colab Tutorial for Beginners for details about using Google Colab for data science projects.

# Mount Google Drive
from google.colab import drive
drive.mount('/content/drive')

# Change directory
import os
os.chdir("drive/My Drive/contents/nlp")

# Print out the current directory
!pwd

Now let’s read the data into a pandas dataframe and see what the dataset looks like.

The dataset has two columns. One column contains the reviews and the other column contains the sentiment label for the review.

# Read in data
amz_review = pd.read_csv('sentiment labelled sentences/amazon_cells_labelled.txt', sep='\t', names=['review', 'label'])

# Take a look at the data
amz_review.head()
Amazon review data for sentiment analysis — GrabNGoInfo.com

.info helps us to get information about the dataset.

# Get the dataset information
amz_review.info()

From the output, we can see that this data set has 1000 records and no missing data. The review column is the object type and the label column is the int64 type.

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 2 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   review  1000 non-null   object
 1   label   1000 non-null   int64 
dtypes: int64(1), object(1)
memory usage: 15.8+ KB

The label value of 0 represents negative reviews and the label value of 1 represents positive reviews. The dataset has 500 positive reviews and 500 negative reviews. It is well-balanced, so we can use accuracy as the metric to evaluate the model performance.

# Check the label distribution
amz_review['label'].value_counts()

Output:

0    500
1    500
Name: label, dtype: int64

Step 3: Train Test Split

In step 3, we will split the dataset and have 80% as the training dataset and 20% as the testing dataset.

Using the sample method, we set frac=0.8, which randomly samples 80% of the data. random_state=42 ensures that the sampling result is reproducible.

Dropping the train_data from the review dataset gives us the rest 20% of the data, which is our testing dataset.

# Training dataset
train_data = amz_review.sample(frac=0.8, random_state=42)

# Testing dataset
test_data = amz_review.drop(train_data.index)

# Check the number of records in training and testing dataset.
print(f'The training dataset has {len(train_data)} records.')
print(f'The testing dataset has {len(test_data)} records.')

After the train test split, there are 800 reviews in the training dataset and 200 reviews in the testing dataset.

The training dataset has 800 records.
The testing dataset has 200 records.

Step 4: Convert Pandas Dataframe to Hugging Face Dataset

In step 4, the training and the testing datasets will be converted from pandas dataframe to Hugging Face Dataset format.

Hugging Face Dataset objects are memory-mapped on the drive, so they are not limited by RAM memory, which is very helpful for processing large datasets.

We use Dataset.from_pandas to convert a pandas dataframe to a Hugging Face Dataset.

# Convert pyhton dataframe to Hugging Face arrow dataset
hg_train_data = Dataset.from_pandas(train_data)
hg_test_data = Dataset.from_pandas(test_data)

The length of the Hugging Face Dataset is the same as the number of records in the pandas dataframe. For example, there are 800 records in the pandas dataframe for the training dataset, and the length of the converted Hugging Face Dataset for the training dataset is 800 too.

hg_train_data[0] gives us the first record in the Hugging Face Dataset. It is a dictionary with three keys, review, label, and __index_level_0__.

  • review is the variable name for the review text. The name is inherited from the column name of the pandas dataframe.
  • label is the variable name for the sentiment of the review text. The name is inherited from the column name of the pandas dataframe too.
  • __index_level_0__ is an automatically generated field from the pandas dataframe. It stores the index of the corresponding record.
# Length of the Dataset
print(f'The length of hg_train_data is {len(hg_train_data)}.\n')

# Check one review
hg_train_data[0]

In this example, we can see that the review is Thanks again to Amazon for having the things I need for a good price!, the sentiment for the review is positive/1, and the index of this record is 521 in the pandas dataframe.

The length of hg_train_data is 800.

{'review': 'Thanks again to Amazon for having the things I need for a good price!',
 'label': 1,
 '__index_level_0__': 521}

Checking the index 521 in the pandas dataframe confirms the same information with Hugging Face Dataset.

# Validate the record in pandas dataframe
amz_review.iloc[[521]]
index_level_0 validation — GrabNGoInfo.com

Step 5: Tokenize Text

In step 5, we will tokenize the review text using a tokenizer.

A tokenizer converts text into numbers to use as the input of the NLP (Natural Language Processing) models. Each number represents a token, which can be a word, part of a word, punctuation, or special tokens. How the text is tokenized is determined by the pretrained model. AutoTokenizer.from_pretrained("bert-base-cased") is used to download vocabulary from the pretrained bert-base-cased model, meaning that the text will be tokenized like a BERT model.

# Tokenizer from a pretrained model
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

# Take a look at the tokenizer
tokenizer

We can see that the tokenizer contains information such as model name, vocabulary size, max length, padding position, truncation position, and special tokens.

BertTokenizerFast(name_or_path='bert-base-cased', vocab_size=28996, model_max_length=512, is_fast=True, padding_side='right', truncation_side='right', special_tokens={'unk_token': '[UNK]', 'sep_token': '[SEP]', 'pad_token': '[PAD]', 'cls_token': '[CLS]', 'mask_token': '[MASK]'})

There are five special tokens for the BERT model. Other models may have different special tokens.

  • The tokens that are not part of the BERT model training dataset are unknown tokens. The unknown token is [UNK] and the ID for the unknown token is 100.
  • The separator token is [SEP] and the ID for the separator token is 102.
  • The pad token is [PAD] and the ID for the pad token is 0.
  • The sentence level classification token is [CLS] and the ID for the classification token is 101.
  • The mask token is [MASK] and the ID for the mask token is 103.
# Mapping between special tokens and their IDs.
print(f'The unknown token is {tokenizer.unk_token} and the ID for the unkown token is {tokenizer.unk_token_id}.')
print(f'The seperator token is {tokenizer.sep_token} and the ID for the seperator token is {tokenizer.sep_token_id}.')
print(f'The pad token is {tokenizer.pad_token} and the ID for the pad token is {tokenizer.pad_token_id}.')
print(f'The sentence level classification token is {tokenizer.cls_token} and the ID for the classification token is {tokenizer.cls_token_id}.')
print(f'The mask token is {tokenizer.mask_token} and the ID for the mask token is {tokenizer.mask_token_id}.')

Output:

The unknown token is [UNK] and the ID for the unkown token is 100.
The seperator token is [SEP] and the ID for the seperator token is 102.
The pad token is [PAD] and the ID for the pad token is 0.
The sentence level classification token is [CLS] and the ID for the classification token is 101.
The mask token is [MASK] and the ID for the mask token is 103.

After downloading the model vocabulary, the method tokenizer is used to tokenize the review corpus.

  • max_length indicates the maximum number of tokens kept for each document.

👉 If the document has more tokens than the max_length, it will be truncated.

👉 If the document has less tokens than the max_length, it will be padded with zeros.

👉 If max_length is unset or set to None, the maximum length from the pretrained model will be used. If the pretrained model does not have a maximum length parameter, max_length will be deactivated.

  • truncation controls how the token truncation is implemented. truncation=True indicates that the truncation length is the length specified by max_length. If max_length is not specified, the max_length of the pretrained model is used.
  • padding means adding zeros to shorter reviews in the dataset. The padding argument controls how padding is conducted.

👉 padding=True is the same as padding='longest'. It checks the longest sequence in the batch and pads zeros to that length. There is no padding if only one text document is provided.

👉 padding='max_length' pads to max_length if it is specified, otherwise, it pads to the maximum acceptable input length for the model.

👉 padding=False is the same as padding='do_not_pad'. It is the default, indicating that no padding is applied, so it can output a batch with sequences of different lengths.

# Funtion to tokenize data
def tokenize_dataset(data):
    return tokenizer(data["review"], 
                     max_length=32, 
                     truncation=True, 
                     padding="max_length")

# Tokenize the dataset
dataset_train = hg_train_data.map(tokenize_dataset)
dataset_test = hg_test_data.map(tokenize_dataset)

After tokenization, we can see that both the training and the testing Dataset have 6 features, 'review', 'label', '__index_level_0__', 'input_ids', 'token_type_ids', and 'attention_mask'. The number of rows is stored with num_rows.

# Take a look at the data
print(dataset_train)
print(dataset_test)

Output:

Dataset({
    features: ['review', 'label', '__index_level_0__', 'input_ids', 'token_type_ids', 'attention_mask'],
    num_rows: 800
})
Dataset({
    features: ['review', 'label', '__index_level_0__', 'input_ids', 'token_type_ids', 'attention_mask'],
    num_rows: 200
})

Next, some data processing is needed to make the training and testing datasets compatible with the model.

  • "review" and "__index_level_0__" are removed because they will not be used in the model.
  • "label" is renamed to "labels" because the model expects the name "labels".
  • The format of the datasets is set to PyTorch tensors.
# Remove the review and index columns because it will not be used in the model
dataset_train = dataset_train.remove_columns(["review", "__index_level_0__"])
dataset_test = dataset_test.remove_columns(["review", "__index_level_0__"])

# Rename label to labels because the model expects the name labels
dataset_train = dataset_train.rename_column("label", "labels")
dataset_test = dataset_test.rename_column("label", "labels")

# Change the format to PyTorch tensors
dataset_train.set_format("torch")
dataset_test.set_format("torch")

# Take a look at the data
print(dataset_train)
print(dataset_test)

After the data processing, we can see that both training and testing datasets have four features.

Dataset({
    features: ['labels', 'input_ids', 'token_type_ids', 'attention_mask'],
    num_rows: 800
})
Dataset({
    features: ['labels', 'input_ids', 'token_type_ids', 'attention_mask'],
    num_rows: 200
})

dataset_train[0] gives us the content for the first record in the training dataset in a dictionary format.

  • 'labels' is the label of the classification. The first record is a positive review, so the label is 1.
  • 'input_ids' are the IDs for the tokens. There are 32 token IDs because the max_length is 32 for the tokenization.
  • 'token_type_ids' is also called segment IDs.

👉 BERT was trained on two tasks, Masked Language Modeling and Next Sentence Prediction. 'token_type_ids' is for the Next Sentence Prediction, where two sentences are used to predict whether the second sentence is the next sentence for the first one.

👉 The first sentence has all the tokens represented by zeros, and the second sentence has all the tokens represented by ones.

👉 Because our classification task does not have a second sentence, all the values for 'token_type_ids' are zeros.

  • 'attention_mask' indicates which token ID should get attention from the model, so the padding tokens are all zeros and other tokens are 1s.
# Check the first record
dataset_train[0]

Output:

{'labels': tensor(1),
 'input_ids': tensor([ 101, 5749, 1254, 1106, 9786, 1111, 1515, 1103, 1614,  146, 1444, 1111,
          170, 1363, 3945,  106,  102,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0]),
 'token_type_ids': tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
         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, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0])}

Step 6: DataLoader

In step 6, we will put the training and testing datasets into DataLoader.

DataLoader is a parallel data loading process by PyTorch. It increases the data loading speed and decreases memory usage.

  • dataset takes the dataset name to put in the DataLoader.
  • shuffle=True indicates that the data will be reshuffled at every epoch. The default value is False. We set it True for the training dataset and keep the default False for the testing dataset.
  • batch_size=4 means that 4 samples will be loaded for each batch. The default value is 1.

Before putting the dataset into DataLoader, the unoccupied cached memory is released by torch.cuda.empty_cache().

# Empty cache
torch.cuda.empty_cache()

# DataLoader
train_dataloader = DataLoader(dataset=dataset_train, shuffle=True, batch_size=4)
eval_dataloader = DataLoader(dataset=dataset_test, batch_size=4)

Step 7: Load Pretrained Model

In step 7, we will load the pretrained model for sentiment analysis.

  • AutoModelForSequenceClassification loads the BERT model without the sequence classification head.
  • The method from_pretrained() loads the weights from the pretrained model into the new model, so the weights in the new model are not randomly initialized. Note that the new weights for the new sequence classification head are going to be randomly initialized.
  • bert-base-cased is the name of the pretrained model. We can change it to a different model based on the nature of the project.
  • num_labels indicates the number of classes. Our dataset has two classes, positive and negative, so num_labels=2.
# Load model
model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=2)

Step 8: Set Learning Rate Scheduler

In step 8, we will set up the learning rate scheduler using the get_scheduler method.

  • name="linear" indicates that the name of the scheduler is linear.
  • optimizer takes AdamW as the optimizer. AdamW is a variation of the Adam optimizer. It modifies the weight decay in Adam by decoupling weight decay from the gradient update. params takes the model parameters. lr is the learning rate.
  • num_warmup_steps=0 indicates that there are no warmup steps.
  • num_training_steps is the number of training steps. It is calculated as the number of epochs times the number of batches. We set the number of epochs to be 2, meaning that the model will go through the whole training dataset 2 times. The number of batches is the length of the training data loader.

Then we set the model to use GPU if it is available.

# Number of epochs
num_epochs = 2

# Number of training steps
num_training_steps = num_epochs * len(train_dataloader)

# Optimizer
optimizer = AdamW(params=model.parameters(), lr=5e-6)

# Set up the learning rate scheduler
lr_scheduler = get_scheduler(name="linear", 
                             optimizer=optimizer, 
                             num_warmup_steps=0, 
                             num_training_steps=num_training_steps)

# Use GPU if it is available
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
model.to(device)

Step 9: PyTorch Training Loop

In step 9, we will run the PyTorch training loop for the transfer learning model.

model.train() tells the model that we are training the model. Some layers work differently for training and evaluation, and model.train() helps to inform the layers that the model training is in progress.

Then the PyTorch training loop runs through each batch for each epoch.

  • Firstly, the data is fetched from the batch and passed into the model.
  • Then, the output of the model is used to calculate the loss and update the weights based on backpropagation results.
  • After that, the learning rate scheduler is executed and the gradients are cleared.
  • Finally, the progress bar is updated to reflect the training progress.
# Set the progress bar
progress_bar = tqdm(range(num_training_steps))

# Tells the model that we are training the model
model.train()
# Loop through the epochs
for epoch in range(num_epochs):
    # Loop through the batches
    for batch in train_dataloader:
        # Get the batch
        batch = {k: v.to(device) for k, v in batch.items()}
        # Compute the model output for the batch
        outputs = model(**batch)
        # Loss computed by the model
        loss = outputs.loss
        # backpropagates the error to calculate gradients
        loss.backward()
        # Update the model weights
        optimizer.step()
        # Learning rate scheduler
        lr_scheduler.step()
        # Clear the gradients
        optimizer.zero_grad()
        # Update the progress bar
        progress_bar.update(1)

Step 10: PyTorch Model Prediction and Evaluation

In step 10, we will talk about how to make model predictions and evaluations using PyTorch.

Hugging Face has an evaluate library with over 100 evaluation modules. We can see the list of all the modules using evaluate.list_evaluation_modules().

# Number of evaluation modules
print(f'There are {len(evaluate.list_evaluation_modules())} evaluation models in Hugging Face.\n')

# List all evaluation metrics
evaluate.list_evaluation_modules()

Output:

There are 129 evaluation models in Hugging Face.

['lvwerra/test',
 'precision',
 'code_eval',
 'roc_auc',
 'cuad',
 'xnli',
 'rouge',
 'pearsonr',
 'mse',
 'super_glue',
 'comet',
 'cer',
 'sacrebleu',
 'mahalanobis',
 'wer',
 'competition_math',
 'f1',
 'recall',
 'coval',
 'mauve',
 'xtreme_s',
 'bleurt',
 'ter',
 'accuracy',
 'exact_match',
 'indic_glue',
 'spearmanr',
 'mae',
 'squad',
 'chrf',
 'glue',
 'perplexity',
 'mean_iou',
 'squad_v2',
 'meteor',
 'bleu',
 'wiki_split',
 'sari',
 'frugalscore',
 'google_bleu',
 'bertscore',
 'matthews_correlation',
 'seqeval',
 'trec_eval',
 'rl_reliability',
 'jordyvl/ece',
 'angelina-wang/directional_bias_amplification',
 'cpllab/syntaxgym',
 'lvwerra/bary_score',
 'kaggle/amex',
 'kaggle/ai4code',
 'hack/test_metric',
 'yzha/ctc_eval',
 'codeparrot/apps_metric',
 'mfumanelli/geometric_mean',
 'daiyizheng/valid',
 'poseval',
 'erntkn/dice_coefficient',
 'mgfrantz/roc_auc_macro',
 'Vlasta/pr_auc',
 'gorkaartola/metric_for_tp_fp_samples',
 'idsedykh/metric',
 'idsedykh/codebleu2',
 'idsedykh/codebleu',
 'idsedykh/megaglue',
 'kasmith/woodscore',
 'cakiki/ndcg',
 'brier_score',
 'Vertaix/vendiscore',
 'GMFTBY/dailydialogevaluate',
 'GMFTBY/dailydialog_evaluate',
 'jzm-mailchimp/joshs_second_test_metric',
 'ola13/precision_at_k',
 'yulong-me/yl_metric',
 'abidlabs/mean_iou',
 'abidlabs/mean_iou2',
 'KevinSpaghetti/accuracyk',
 'Felipehonorato/my_metric',
 'NimaBoscarino/weat',
 'ronaldahmed/nwentfaithfulness',
 'Viona/infolm',
 'kyokote/my_metric2',
 'kashif/mape',
 'Ochiroo/rouge_mn',
 'giulio98/code_eval_outputs',
 'leslyarun/fbeta_score',
 'giulio98/codebleu',
 'anz2/iliauniiccocrevaluation',
 'zbeloki/m2',
 'xu1998hz/sescore',
 'mase',
 'mape',
 'smape',
 'dvitel/codebleu',
 'NCSOFT/harim_plus',
 'JP-SystemsX/nDCG',
 'sportlosos/sescore',
 'Drunper/metrica_tesi',
 'jpxkqx/peak_signal_to_noise_ratio',
 'jpxkqx/signal_to_reconstrution_error',
 'hpi-dhc/FairEval',
 'nist_mt',
 'lvwerra/accuracy_score',
 'character',
 'charcut_mt',
 'ybelkada/cocoevaluate',
 'harshhpareek/bertscore',
 'posicube/mean_reciprocal_rank',
 'bstrai/classification_report',
 'omidf/squad_precision_recall',
 'Josh98/nl2bash_m',
 'BucketHeadP65/confusion_matrix',
 'BucketHeadP65/roc_curve',
 'mcnemar',
 'exact_match',
 'wilcoxon',
 'ncoop57/levenshtein_distance',
 'kaleidophon/almost_stochastic_order',
 'word_length',
 'lvwerra/element_count',
 'word_count',
 'text_duplicates',
 'perplexity',
 'label_distribution',
 'toxicity',
 'prb977/cooccurrence_count',
 'regard',
 'honest',
 'NimaBoscarino/pseudo_perplexity']

We will use three metrics to evaluate the model performance. They are accuracy, f1, and recall.

  • accuracy is the percentage of correct predictions. It ranges from 0 to 1, where 1 means perfect prediction. The higher value the accuracy is, the better the model is when the data is balanced.
  • recall is also called sensitivity or true positive rate. It is the percentage of positive events captured out of all the positive events. The value for recall ranges from 0 to 1. The higher value the recall is, the better the model is.
  • f1 is a metric that balances precision and recall values, and it should be used when there is no clear preference between precision and recall. The F1 score ranges from 0 to 1, with the best value being 1 and the worst value being 0.
# Load the evaluation metric
metric1 = evaluate.load("accuracy")
metric2 = evaluate.load("f1")
metric3 = evaluate.load("recall")

The prediction and evaluation process starts with model.eval(), which tells PyTorch that we are evaluating the model instead of training the model.

Because the model evaluation is processed in batches, empty lists are created to hold all the prediction results for logits, predicted probabilities, and predicted labels.

# Tells the model that we are evaluting the model performance
model.eval()

#  A list for all logits
logits_all = []

# A list for all predicted probabilities
predicted_prob_all = []

# A list for all predicted labels
predictions_all = []

The model predictions and evaluations are completed in the same loop for the batches. Note that since this is the prediction step, no epoch is needed.

  • Firstly, we get the data from the batch and pass it to the model for prediction. torch.no_grad() is included to disable the gradient calculation. The gradient calculation is disabled for the prediction because it is only needed for the training process.
  • Then logits are extracted from the prediction output and appended to the list logits_all. Logit values from all classes do not sum up to 1.
  • To get the predicted probabilities, torch.softmax is applied on the logits. dim=1 means that the softmax is calculated based on the rows, so for each sample, the predicted probabilities for all classes sum up to 1.
  • The label prediction can be based on either logits or predicted probabilities. In this example, we are using logits, but the predicted probabilities should give the same results. dim=-1 means that the last column is the event of interest.
  • After having the predictions, the model performance metrics are calculated. references takes the true labels for the batch.
# Loop through the batches in the evaluation dataloader
for batch in eval_dataloader:
    # Get the batch
    batch = {k: v.to(device) for k, v in batch.items()}
    # Disable the gradient calculation
    with torch.no_grad():
        # Compute the model output
        outputs = model(**batch)
    # Get the logits
    logits = outputs.logits
    # Append the logits batch to the list
    logits_all.append(logits)
    # Get the predicted probabilities for the batch
    predicted_prob = torch.softmax(logits, dim=1)
    # Append the predicted probabilities for the batch to all the predicted probabilities
    predicted_prob_all.append(predicted_prob)
    # Get the predicted labels for the batch
    predictions = torch.argmax(logits, dim=-1)
    # Append the predicted labels for the batch to all the predictions
    predictions_all.append(predictions)
    # Add the prediction batch to the evaluation metric
    metric1.add_batch(predictions=predictions, references=batch["labels"])
    metric2.add_batch(predictions=predictions, references=batch["labels"])
    metric3.add_batch(predictions=predictions, references=batch["labels"])

# Compute the metric
print(metric1.compute())
print(metric2.compute())
print(metric3.compute())

The evaluation results show that the model has 0.945 accuracy, 0.943 f1 score, and 0.929 recall value.

{'accuracy': 0.945}
{'f1': 0.9430051813471502}
{'recall': 0.9285714285714286}

logits_all[:5] gives us the first 5 batches of logits. We can see that the prediction has two columns. The first column is the predicted logit for label 0 and the second column is the predicted logit for label 1. Each batch has four samples.

# Take a look at the logits
logits_all[:5]

Output:

[tensor([[-1.4175,  1.7728],
         [-1.4442,  1.8167],
         [-1.2888,  1.7954],
         [ 1.1902, -1.3435]], device='cuda:0'), tensor([[ 1.0639, -1.3628],
         [-1.3469,  1.6955],
         [ 0.8422, -1.3144],
         [ 1.1680, -1.4845]], device='cuda:0'), tensor([[-1.0588,  1.3745],
         [ 1.2833, -1.2503],
         [-1.5322,  1.5994],
         [ 0.1853, -0.6757]], device='cuda:0'), tensor([[-0.9469,  1.0366],
         [-0.8427,  1.0451],
         [-1.3804,  1.6149],
         [ 0.8212, -1.0765]], device='cuda:0'), tensor([[ 0.9545, -1.2628],
         [-1.4912,  1.8893],
         [-1.4786,  1.6621],
         [ 1.4001, -1.4412]], device='cuda:0')]

predicted_prob_all[:5] gives the first five batches of the predicted probabilities. We can see that the sum of each row adds up to 1.

# Take a look at the predicted probabilities
predicted_prob_all[:5]
[tensor([[0.0395, 0.9605],
         [0.0369, 0.9631],
         [0.0438, 0.9562],
         [0.9265, 0.0735]], device='cuda:0'), tensor([[0.9188, 0.0812],
         [0.0455, 0.9545],
         [0.8963, 0.1037],
         [0.9342, 0.0658]], device='cuda:0'), tensor([[0.0807, 0.9193],
         [0.9265, 0.0735],
         [0.0418, 0.9582],
         [0.7029, 0.2971]], device='cuda:0'), tensor([[0.1209, 0.8791],
         [0.1315, 0.8685],
         [0.0476, 0.9524],
         [0.8696, 0.1304]], device='cuda:0'), tensor([[0.9018, 0.0982],
         [0.0329, 0.9671],
         [0.0415, 0.9585],
         [0.9449, 0.0551]], device='cuda:0')]

predictions_all[:5] gives the first five batches of the predicted labels. We can see that the ones correspond to the higher value of logits and the zeros correspond to the lower value of the logits for each sample.

# Take a look at the predicted labels
predictions_all[:5]

Output:

[tensor([1, 1, 1, 0], device='cuda:0'),
 tensor([0, 1, 0, 0], device='cuda:0'),
 tensor([1, 0, 1, 0], device='cuda:0'),
 tensor([1, 1, 1, 0], device='cuda:0'),
 tensor([0, 1, 1, 0], device='cuda:0')]

Step 11: Save and Load Model

In step 11, we will talk about how to save the model and reload it for prediction.

tokenizer.save_pretrained saves the tokenizer information to the drive and model.save_model saves the model to the drive.

# Save tokenizer
tokenizer.save_pretrained('./sentiment_transfer_learning_pytorch/')

# Save model
model.save_pretrained('./sentiment_transfer_learning_pytorch/')

We can load the saved tokenizer later using AutoTokenizer.from_pretrained() and load the saved model using AutoModelForSequenceClassification.from_pretrained().

# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained("./sentiment_transfer_learning_pytorch/")

# Load model
loaded_model = AutoModelForSequenceClassification.from_pretrained('./sentiment_transfer_learning_pytorch/')

More tutorials are available on GrabNGoInfo YouTube Channel, GrabNGoInfo.com, and LinkedIn.

Recommended Tutorials

References

Text Classification
Hugging Face
Pytorch
Naturallanguageprocessing
NLP
Recommended from ReadMedium