Ayşegül Gürmeriç
CITS Tech
Published in
10 min readJan 24, 2023

--

Makine Öğrenme Frameworkleri (BERT)

Her ne kadar bir makine öğrenmesi veya doğal dil işlemesi uzmanı olmasam da, bu yazıda böyle bir uzmanlığınız olmasa bile ihtiyacınıza göre kullanabileceğiniz hazır yüksek seviyeli bir framework olan BERT i anlatmaya ve python tabanlı temel bir örnek vermeye çalışacağım. Bu sistemi daha önce öğrencilerin online sınavlarında yaptıkları gramer hatalarını eğitmenlere bildirmek amacı ile kullandığımdan temel bir tecrübem olduğunu söyleyebilirim. Yazımda, BERT kapsamında hazırlanan nöral network sistemini veya doğal dil işlemenin derin tekniklerini değil, framework ün temel kullanımını açıklayacağım. Umarım sizin de projelerinizde ihtiyaçlarınızı karşılar.

Google ın hazırladığı bu sistem [1,6,7] kendi arama motorlarında, dil çevirme algoritmalarında ve yazı özetleme gibi işlemlerde temel olarak kullanılıyor. BERT kelimesi Bidirectional Encoder Representations from Transformers kelimelerinin kısaltmasından geliyor. Doğal dil işleme amacıyla hazırlanan BERT sistemi transformer tabanlı bir makine öğrenmesi yapısı olarak tanımlanıyor.

BERT in son yıllarda birçok dil işleme problemine zemin olarak kullanılan ve bu alanda çalışanlar için popüler olan bir yapı olduğunu söyleyebilirim. Diğer alternatiflerine göre başarısı, iyi bilinen NLP task ları olan GLUE, MultiNLI ve SQuAD gibi çalışmaların derecelendirme tablolarında da görülebilir [1, bölüm 4–5]. Ayrıca BERT hem sağdan sola hem de soldan sağa yazılan dillere ayak uydurabilecek şekilde tasarlanmış bir sistem.

Kısaca açıklamam gerekirse; bir yazı kapsamında kelimelerin birbirleri ile olan içerik alakasını öğrenen bu yapı, eğitildiği dilin modelini çıkartabiliyor. Google ın Wikipedia ve BookCorpus içeriklerini önden eğiterek oluşturduğu bu derin nöral network sisteminin modelleri hazır olarak indirilebiliyor. Ön eğitimli bu modeller temelde BERT BASE ve BERT LARGE olarak 2 şekilde kullanıma sunulmuş durumda. İsimlerinden de anlayacağınız üzere LARGE daha kapsamlı ve daha çok nöron barındıracak şekilde eğitilmiş bir model. İhtiyacınıza ve projenizin büyüklüğüne göre istediğinizi seçip ilerlemeniz mümkün. Bu modeli aldıktan sonra sizin kullanım amacınıza göre eğitimine devam etmeniz ve sizi hedefe götürecek son çözümü oluşturmanız gerekiyor.

Günlük kullanımda ne işe yarayacağı sorusuna gelince. BERT sistemi:

· Yazı sınıflandırma,

· Yazı özetleme,

· Yazı oluşturma,

· Kısa soru cevaplama,

· Dil çevrimi

gibi alanlarda çözümler oluşturmak için kullanılabiliyor. Fakat ne için kullanacağınız tabi ki biraz sizin hayal gücünüz ve ihtiyaçlarınızla alakalı da diyebiliriz.

Ek Bilgiler:

BERT i anlayabilmek için Encoder/Decoder ve Transformer gibi doğal dil işleme yapılarının ne olduğunu yüzeysel olarak bilmek iyi olur. Bu nedenle elimden geldiği ve benim anladığım kadar açıklamaya çalışayım.

Encoder/Decoder:

Doğal dil işlemenin çeviri amaçlı süreçlerinde makine dili çevrimi adı verilen ara bir işlem vardır. Kısaca bir örnekle açıklamak istiyorum. Eğer bir kelime serisini A dilinden B diline çevirmek istiyorsanız. Öncelikle A dilini sanal bir sayısal makine diline sonrasında da bu makine dilinden B diline çevirirsiniz. A dilinden sayısal vektörler şeklindeki makine diline çevirme işlemi Encoding olarak adlandırılır. Decoding ise bu sayıların B diline çevrilmesi işlemidir. Bu işlemleri yapan nöral yapılar ise Encoder ve Decoder olarak adlandırılır.

Transformer:

Bir transformer mekanizması birbirine karmaşık olarak bağlanmış Encoder ve Decoder üniteleri ile bunlara bağlı bir diğer nöral network sisteminin belirli bir kelime dizisini işleyerek çevirmesi için kurgulanmış yapı olarak tarif edilebilir.

Transformer yapısı [2, Vaswani et al.]

BERT Kullanımı:

Daha önce de söylediğim gibi BERT yeni çözümlere ulaşmak için önceden eğitilmiş bir derin nöral network yapısıdır. Bu anlamda öncelikle BERT in hazırlanmış paketini alarak kendi hedefinize uygun bir şekilde sistemi eğitmeniz gerekiyor ki kendi probleminizi çözebilin. Google bu amaçla farklı parametrik ayarları ve nöral network formları bulunan ön eğitimli BERT modellerini açık bir git repository si [7] olarak vermektedir. İhtiyacınız olan paketi indirdikten sonra veri hazırlama ve model eğitimi süreçlerini tamamlayarak hedeflediğiniz çözüm modelini üretebilirsiniz.

Veri Hazırlama:

Probleminize çözüm üretmek için ilk yapılması gereken eğitim ve test veri setlerinin hazırlanması. BERT sistemine bu veriyi aktarabilmek için tarif edilen şekilde her kelimeyi etiketlemeniz ve fine-tuning adı verilen eğitim süreci için cümle başlarına ve ayraçlarına özel işaretler koymanız gerekiyor (tokenizing) [3,4,5]. Bu işlemlere ek olarak her kelime ve token ardışık integer değerler ile numaralandırılmalı. Özellikle paragraf içeriğinin anlaşılması gereken projelerde her ardışık iki cümleyi birbirine bağlı şekilde etiketliyoruz ki sistem cümleler arası bağ kurabilecek şekilde eğitilebilsin. Bunların dışında bir de arada bazı kelimeleri MASK etiketiyle sisteme vermeniz yani o kelimeyi kapatmanız öneriliyor ki sistem bunları kendiliğinden tahmin edecek şekilde gelişsin. Örnek iki cümleyi aşağıdaki resimde görebilirsiniz.

BERT tokenizing işlemi (word embedding) [1, Devlin et al. 2018]

Genel olarak cümle çiftleri token denilen özel bir işaretle başlatılıyor. Resimdeki örnekte aranan çözüm sınıflandırma olduğu için [CLS] yani classification şeklinde işaretlenmiş. Sonrasında sırasıyla kelimeleri sisteme aktarıyoruz. Bunların arasında kapatmak istediğiniz bazı kelimelere [MASK] token ı ekliyoruz. Son olarak cümleler arasına [SEP] token ı konuluyor. Bu işlemleri tüm yazı için yaptıktan sonra verilen içeriğin sınıfını da sisteme bildirecek halde veriyi hazırlamış oluyoruz. Bu arada python için hazırlanan BERT sınıfları içerisinde anlattığım tokenizing işlemlerini gerçekleştiren yardımcı sınıflar mevcut. Ayrıca her cümledeki kelime ve token sayısının eşit olması gerektiğini (ör: 32,64 …), ve kelimelerin bitiminde kalan alanlara [PAD] token ı eklemeniz gerektiğini unutmayın. Benim örneğimde paragraf anlamlandırma değil sadece cümlelerin doğru yada yanlış olarak işaretlenmesi amaç olduğundan biraz daha farklı bir işlem yaptığımı da göz önünde bulundurun.

Eğitim (fine-tuning):

Veri hazırlama sonrası ön eğitimli BERT sistemine işaretlenmiş verinin yüklenmesi ve eğitimin başlatılması aşamalarına geçiyoruz. Bu aşamada daha önce de söylediğim gibi BERT in Base, Large ve bunlara bağlı Monolingual, Multilingual, Cased, Uncased… gibi temel paketlerinden birini alıyoruz. Bu temel yapılar probleminize göre bazı negatif veya pozitif durumlara neden olabilir. Bazı seçtiğiniz BERT modelleri çok fazla donanım ihtiyacı, eğitim datası, eğitim zamanı gerektirebilir veya çözümünüzün kalitesini etkileyebilir. Yine de BERT diğer alternatiflerine göre çok daha az kaynak ihtiyacına sahip bir sistem diyebiliriz.

BERT sistemi eğitim sırasında iki aşaması vardır [1]:

1. Masked LM:

Bu aşamada BERT, eğitim veri setinde üzeri kapatılmış olan kelimelerin tahmin edilmesi için geliştirir.

2. Next Sentence Prediction (NSP):

Bir sonraki cümlenin tahmin edilmesi aşamasında sistem iki cümle arasındaki içerik bağlantısını anlamaya çalışacak şekilde gelişir.

Uygulama:

Daha önce gerçekleştirdiğim projedeki veri setini kullanmam uygun olmayacağından bu örnekte modelin eğitimi için gerekli veriyi CoLA (The Corpus of Linguistic Acceptability) setinden [8] aldım. Bu veri setinde eğitim cümleleri ve bunların gramer açısından doğruluk etiketleri mevcut. Ortaya çıkan model dosyası çok büyük olduğundan ve eğitim işlemi vakit aldığından Google colab kullanarak eğitimi tamamladım. Colab ın “cuda” desteğini açarsanız çok daha hızlı sonuç aldığınızı söylememe gerek yok sanırım. Bu durumda kodda değişiklik yapıp “cpu” yerine “cuda” seçimi yapmanız gerekiyor. Sonuçta oluşan model dosyası yaklaşık 420 MB kadar. Eğitimle uğraşmak istemeyenler ile dosyayı paylaşabilirim. Benim oluşturduğum 10 cümlelik deneme seti için %70 kadar başarı sağlıyor. CoLa setinin test verisi için ise bu oran %79.7 çıktı. GLUE benchmark testlerinde, diğer sistemler ile karşılaştırma tablosunu aşağıda bulabilirsiniz.

GLUE test sonuç tablosu

Eğitim Kodu:

Aşağıda BERT modelini eğiten (fine-tuning) kod örneğini bulabilirsiniz.

import torch
import random
import wget
import os
import pandas as pd
import numpy as np
import time
import datetime
from transformers import BertTokenizer
from torch.utils.data import TensorDataset, random_split
from transformers import BertForSequenceClassification, AdamW, BertConfig
from transformers import get_linear_schedule_with_warmup
import matplotlib.pyplot as plt
import seaborn as sns
from torch.utils.data import DataLoader, RandomSampler, SequentialSampler

# Torch için kullanılacak işlemci - ekran kartınız uygun değise cpu kullanıyoruz.
device = torch.device("cpu")

# Eğitim seti dosyasını yüklüyoruz.
df = pd.read_csv("./cola_public/raw/in_domain_train.tsv", delimiter='\t', header=None, names=['sentence_source', 'label', 'label_notes', 'sentence'])

# Ekrana toplam cümle sayısını yazıyoruz.
print('Number of training sentences: {:,}\n'.format(df.shape[0]))

df.sample(10)
print(df.loc[df.label == 0].sample(5)[['sentence', 'label']])

sentences = df.sentence.values
labels = df.label.values

# Bert Base modeli alıyoruz.
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased', do_lower_case=True)

# İlk cümle için token örneğini ekrana yazıyoruz.
print('Sentence: ', sentences[0])
print('Tokenized: ', tokenizer.tokenize(sentences[0]))
print('Token code: ', tokenizer.convert_tokens_to_ids(tokenizer.tokenize(sentences[0])))

max_len = 0

# Tüm cümlelere bakarak max kelime içeren cümledeki kelime sayısını alıyorum.
# Bu kısım gözle kontrol etmek için.
for sent in sentences:
input_ids = tokenizer.encode(sent, add_special_tokens=True)
max_len = max(max_len, len(input_ids))

print('Max sentence length: ', max_len)

input_ids = []
attention_masks = []

# Deneme setindeki tüm cümleleri token işleminden geçiriyoruz.
for sentence in sentences:
encoded_dict = tokenizer.encode_plus(
sentence,
add_special_tokens = True,
max_length = 64,
pad_to_max_length = True,
return_attention_mask = True,
return_tensors = 'pt',
)

input_ids.append(encoded_dict['input_ids'])
attention_masks.append(encoded_dict['attention_mask'])

# Yüklediğimiz verileri pytorch ile kullanabilmek için Tensor setlerine ceviriyoruz ve batch gruplara ayırıyoruz.
input_ids = torch.cat(input_ids, dim=0)
attention_masks = torch.cat(attention_masks, dim=0)
labels = torch.tensor(labels)

dataset = TensorDataset(input_ids, attention_masks, labels)

# Eğitim için kullanılacak cümleleri eğitim ve validation şeklinde 2 set e bölüyoruz
# Oran %90 a %10
train_size = int(0.9 * len(dataset))
val_size = len(dataset) - train_size

train_dataset, val_dataset = random_split(dataset, [train_size, val_size])

print('{:>5,} training samples'.format(train_size))
print('{:>5,} validation samples'.format(val_size))


# 32 lik gruplar halinde eğitime random olarak veri hazırlıyoruz.
batch_size = 32
train_dataloader = DataLoader(train_dataset, sampler = RandomSampler(train_dataset), batch_size = batch_size)
validation_dataloader = DataLoader(val_dataset, sampler = SequentialSampler(val_dataset), batch_size = batch_size)


# Bert Base modeli alıyoruz (Sınıflandırma amaçlı).
model = BertForSequenceClassification.from_pretrained("bert-base-uncased", num_labels = 2, output_attentions = False, output_hidden_states = False,)
model.cpu()
params = list(model.named_parameters())

# Bu çalışmada optimizer olarak adam hızlı sonuç verdi.
# Farklı optimizerlar deneyebilirsiniz.
optimizer = AdamW(model.parameters(), lr = 2e-5 )

# Eğitimin ilerlemesini kontrol etmek için gerekli fonksiyonlar ve değerler

# Max eğitim iterasyon sayısı. Bert sistemini oluşturanlar max 4 yapmayı öneriyor. Sonrası overfitting e giriyor.
# Bu kısmı başarımdaki ilerlemeye göre kesmek te mümkün.
epochs = 4
total_steps = len(train_dataloader) * epochs

scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps = 0, num_training_steps = total_steps)

def flat_accuracy(preds, labels):
pred_flat = np.argmax(preds, axis=1).flatten()
labels_flat = labels.flatten()
return np.sum(pred_flat == labels_flat) / len(labels_flat)

def format_time(elapsed):
elapsed_rounded = int(round((elapsed)))
return str(datetime.timedelta(seconds=elapsed_rounded))



# Weight ve Bias değerlerinin random set edilmesi için elden bir seed seçtim.
# Bir hata görürsem aynı işlemi tekrarlayabilmek için sabit bir seed verdim.
# Bunu tamamen random da alabilirsiniz.
seed_val = 42

random.seed(seed_val)
np.random.seed(seed_val)
torch.manual_seed(seed_val)
torch.cuda.manual_seed_all(seed_val)

training_stats = []
total_t0 = time.time()

# Eğitim bu döngüde seçtiğim epoch sayısı kadar ilerleyecek
# Bu kısmın başarım grafiğine göre yapılması daha doğru ama ben çok vaktim olmadığından sabit tuttum.
# Siz başarı grafiğinin tepesinde döngüyü keseblirsiniz.
for epoch_i in range(0, epochs):

t0 = time.time()
total_train_loss = 0

# modeli bir iterasyon eğitiyoruz
model.train()

# Eğitim cümlelerindeki tüm gruplar için
for step, batch in enumerate(train_dataloader):
if step % 40 == 0 and not step == 0: # 40 iterasyonda bir geçen zamanı bir değişkene alıyorum.
elapsed = format_time(time.time() - t0)

b_input_ids = batch[0].to(device)
b_input_mask = batch[1].to(device)
b_labels = batch[2].to(device)

# Forward pass kısmında modeli eğitim veri grubuyla besliyoruz.
# Eski türev tablosunu 0 lıyoruz.
model.zero_grad()

outputs = model(b_input_ids,
token_type_ids=None,
attention_mask=b_input_mask,
labels=b_labels)

loss, logits = outputs[:2]

# Loss fonsiyonundan ilerleme değerlerini alıyoruz.
total_train_loss += loss.item()

# Backpropagation hesaplarını yaptırıyoruz.
loss.backward()

# Weight ve bias değerlerini 0-1 arasında tutmaya çalışıyoruz.
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)

# optimizer ın yeni step i seçmesini sağlıyoruz.
optimizer.step()
scheduler.step()

# Ortalama ilerlemeyi ve zamanı kaydediyoruz.
avg_train_loss = total_train_loss / len(train_dataloader)
training_time = format_time(time.time() - t0)

print("")
print(" loss: {0:.2f}".format(avg_train_loss))

# Validasyon aşaması
print("")

t0 = time.time()
model.eval()
total_eval_accuracy = 0
total_eval_loss = 0
nb_eval_steps = 0

# Tüm validasyon seti cümle grupları için
for batch in validation_dataloader:
b_input_ids = batch[0].to(device)
b_input_mask = batch[1].to(device)
b_labels = batch[2].to(device)

with torch.no_grad(): # O ana kadar eğitilmiş olan modele validation setinden tahmin yapmasını istiyoruz.

outputs = model(b_input_ids,
token_type_ids=None,
attention_mask=b_input_mask,
labels=b_labels)

loss, logits = outputs[:2]

total_eval_loss += loss.item()

logits = logits.detach().cpu().numpy()
label_ids = b_labels.to('cpu').numpy()

# Başarımı hesaplıyoruz.
total_eval_accuracy += flat_accuracy(logits, label_ids)

# Ortalama ilerlemeyi ve başarımı hesaplayıp ekrana yazıyoruz.
avg_val_accuracy = total_eval_accuracy / len(validation_dataloader)
print(" Accuracy: {0:.2f}".format(avg_val_accuracy))

avg_val_loss = total_eval_loss / len(validation_dataloader)
validation_time = format_time(time.time() - t0)

# İlerlemeler için istatistik bilgiler tutuyoruz.
print(" Validation Loss: {0:.2f}".format(avg_val_loss))
print(" Validation took: {:}".format(validation_time))
training_stats.append(
{
'epoch': epoch_i + 1,
'Training Loss': avg_train_loss,
'Valid. Loss': avg_val_loss,
'Valid. Accur.': avg_val_accuracy,
'Training Time': training_time,
'Validation Time': validation_time
}
)

# Tüm eğitim sonrası elimizdeki modeli dosyaya kaydediyoruz.
torch.save(model.state_dict(), 'model.ai')

Test Kodu:

Aşağıda hazırlanmış bir modelin nasıl kullanılacağını bulabilirsiniz.

import torch
import random
import pandas as pd
from numpy import exp
from transformers import BertTokenizer
from torch.utils.data import TensorDataset, random_split
from transformers import BertForSequenceClassification, AdamW, BertConfig
from transformers import BertForSequenceClassification, AdamW, BertConfig
from torch.utils.data import DataLoader, RandomSampler, SequentialSampler

# Torch un kullanacağı işlemciyi seçiyoruz. Benim ekran kartım desteklemediğinden
# ve test te çok hıza ihtiyaç olmadığından cpu yeterli.
device = torch.device("cpu")

# Softmax fonksiyonu:
def softmax(vector):
e = exp(vector)
return e / e.sum()

# Bert Base modeli alıyoruz (Sınıflandırma amaçlı).
model = BertForSequenceClassification.from_pretrained(
"bert-base-uncased",
num_labels = 2,
output_attentions = False,
output_hidden_states = False,
)

# Daha önceden eğittiğimiz fine-tuned modeli üzerine yüklüyoruz.
model.load_state_dict(torch.load('model.ai',map_location=torch.device('cpu')))
model.eval()
model.cpu()

# Test seti dosyasını yüklüyoruz.
#df = pd.read_csv("./cola_public/raw/out_of_domain_dev.tsv", delimiter='\t', header=None, names=['sentence_source', 'label', 'label_notes', 'sentence'])
df = pd.read_csv("./cola_public/raw/mytest.tsv", delimiter='\t', header=None, names=['sentence_source', 'label', 'label_notes', 'sentence'])

# Test setindeki toplam cümle sayısını ekrana yazıyoruz.
print('')
print('Sentence count: {:,}'.format(df.shape[0]))

sentences = df.sentence.values
labels = df.label.values

input_ids = []
attention_masks = []

# Bert tokenizer sınıfından projemize uygun tokenizer objesi yaratıyouz.
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased', do_lower_case=True)

# İlk cümle için token örneğini ekrana yazıyoruz.
print('')
print('Sentence: ', sentences[0])
print('Tokenized: ', tokenizer.tokenize(sentences[0]))
print('Tokens: ', tokenizer.convert_tokens_to_ids(tokenizer.tokenize(sentences[0])))
print('')

# Deneme setindeki tüm cümleleri token işleminden geçiriyoruz.
for sentence in sentences:
encoded_dict = tokenizer.encode_plus(sentence, add_special_tokens = True, truncation=True, max_length = 64, pad_to_max_length = True, return_attention_mask = True, return_tensors = 'pt',)
input_ids.append(encoded_dict['input_ids'])
attention_masks.append(encoded_dict['attention_mask'])

# Cümleleri 32 lik gruplar halinde alıyoruz daha fazlasına bilgisayarımın ram i yetmeyebiliyor.
batch_size = 32

# Yüklediğimiz verileri pytorch ile kullanabilmek için Tensor setlerine ceviriyoruz ve batch gruplara ayırıyoruz.
input_ids = torch.cat(input_ids, dim=0)
attention_masks = torch.cat(attention_masks, dim=0)
labels = torch.tensor(labels)

prediction_data = TensorDataset(input_ids, attention_masks, labels)
prediction_sampler = SequentialSampler(prediction_data)
prediction_dataloader = DataLoader(prediction_data, sampler=prediction_sampler, batch_size=batch_size)


corrects = 0

# Tüm cümle gruplarını (32 lik) elimizdeki modele işleterek sonuçlarını alıyoruz ve tahminleri olması gereken sonuçlarla karşılaştırıyoruz.
# Gruplar halinde modele sormak daha hızlı olduğu için tek tek yapmadım.
for batch in prediction_dataloader:
batch = tuple(t.to(device) for t in batch)
b_input_ids, b_input_mask, b_labels = batch

out = model(b_input_ids, token_type_ids=None, attention_mask=b_input_mask)
logits = out[0]
logits = logits.detach().cpu().numpy()
label_ids = b_labels.to('cpu').numpy()

print('')

i=0
# Cümle grubundaki tüm tahminler için:
for prediction in logits:
#Tahmini softmax ile doğrultuyoruz.
sm = softmax(prediction.tolist())
mx = max(sm)
cl = sm.tolist().index(mx)
# Cümleyi ekrana yazıyoruz.
print('')
print('"', df['sentence'][i], '":')
print(prediction, sm, cl, label_ids[i])
# Eğer tahmin veri setindeki işaretlemesine uygunsa doğru bir tahmindir.
if cl==label_ids[i]:
corrects+=1 # doğruları sayıyoruz.
i=i+1;

print('')
print('Correct:',corrects,'/',len(sentences),' = ',corrects/len(sentences))
Test kodu ekran çıktısı.

Referanslar

[1] BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding, J. Devlin, M. Chang, K. Lee, and K. Toutanova.,NAACL-HLT (1) , page 4171–4186. Association for Computational Linguistics, (2019)

[2] Attention is All you Need,

A. Vaswani, N. Shazeer, N. Parmar, J. Uszkoreit, L. Jones, A. Gomez, Ł. Kaiser, and I. Polosukhin. Advances in Neural Information Processing Systems 30, Curran Associates, Inc., (2017)

[3] Google BERT NLP Machine Learning Tutorial,

Milecia McGregor, https://www.freecodecamp.org/news/google-bert-nlp-machinelearning-tutorial/

[4] BERT Explained: State of the art language model for NLP,

Rani Horev, https://towardsdatascience.com/bert-explained-state-of-the-artlanguage-model-for-nlp-f8b21a9b6270

[5] Understanding searches better than ever before,

Pandu Nayak, Google Blog, https://blog.google/products/search/search-languageunderstanding-bert/

[6] BERT model,

Wikipedia, https://en.wikipedia.org/wiki/BERT_(language_model)

[7] BERT git repository, Google,

https://github.com/google-research/bert

https://github.com/google-research/bert#pre-trained-models

[8] CoLa Dataset http://nyu-mll.github.io/cola

--

--