emotions = load_datat('emotion')
emotions
emotions.keys()
print(emotions['train'],type(emotions['train']))
print(emotions['train']['text'][:5])
print(emotions['train']['label'][:5])
print(emotions['train'][:5])
print(emotions['train'].features)
print(emotions['train'].features['label'])
print(emotions['train'].features['label'].int2str(2))
labels = emotional['train'].features['label'].name
print(labels)
num_classes = len(labels)
num_classes
Data Visualization analysis
- dataset->dataframe
- text length
- label freq
dataset to dataframe
emotions_df = pd.DataFrame.from_dict(emotions['train'])
print(emotions_df.shape,emotions_df.columns)
emotions_df[:5]
emotions_df['label_name']=emotions_df['label'].apply(lamada x:labels(x))
emotions_df[:5]
data analysis
各个类别的数量:
emotions_df.labels.value_counts()
emotions_df.labels_name.value_counts()
plt.figure(figsize = (4,3))
emotions_df['label_name'].value_counts(ascending=True).plot.barh()
plt.title('freq of lanels')
text length analysis
plt.figure(figsize=(4,3))
emotions_df['words per tweet']=emotions_df['text'].str.split().apply(len)
emotions_df.boxplot('word per tweet',by='label_name',showliers=False,grid=False,color='black')
plt.subtitle(' ')
plt.xlabel(' ')
print(emotions_df['words per tweet'].max())
print(emotions_df['words per tweet'].idmax())
print(emotions_df.iloc[6322])
emotions_df.iloc[6322]['text']
print(emotions_df['words per tweet'].min())
print(emotions_df['words per tweet'].idmin())
print(emotions_df.iloc[6322])
emotions_df.iloc[6322]['text']
text==>token
将数据集转换为模型接受的输入的类型
- Subword Tokenization
- WordPiece
- Bert And DistilBERT
- WordPiece
- huggingface
-/.cache/huggingface/
- tokenizer
tokenizer.vocab_size- model config
tokenizer.model_max_lengthtokenizer.model_input_names
tokenizer
from transformers import AutoTokenizer
model_ckpt = 'distilbert-base-uncased'
tokenizer = AutoTokenizer.from_pretrained(model_ckpt)
#uncased
print(tokenizer.encode('Hello World')
print(tokenizer.encode('HELLO WORLD')
print(tokenizer.encode('hello world')
print(tokenizer.vocab_size)
print(tokenizer.model_max_length)
print(tokenizer.model_input_name)
#special_id
for special_id in tokenizer.all_special_ids:
print(special_id,tokenizer.decode(special_id))
tokenize the whole dataset
def batch_tokenize(batch):
return tokenizer(batch['text'],padding=True,truncation=True)
emotions_encoded = emotions.map(batch_tokenizer,batched=True,batch_size=None)
emotions_encoded
type(emotions_encoded['train']['input_ids'])
emotions_encoded.set_format('torch',column=['label','input_ids','attention_mask'])
type(emotions_encoded['train']['input_ids'])
fine-tune transformers
distilbert-case-uncased
- distilbert 是对 bert的distil 而来的
- 模型的结构更为简单
- 比 bert-base-uncased 参数量少不少
from transformers import AutoModel
model_ckpt = 'distilbert-base-uncased'
model = AutoModel.from_pretrained(model_ckpt)
model
from transformers import AutoModelForSequenceClassification
model_ckpt = 'distilbert-base-uncased'
device = torch.device('cuda' if torch.cuda.is_aviailable() else 'cpu')
model = AutoModelForSqeunceClassification.from_pretrained(model_ckpt,num_labels=num_classes).to(device)
model
和AutoModel的区别 多了一个下游任务
trainer
# (write)
from transformers import notebook_login
notebook_login
from transformers import TraimingArgyments,Trainer
batch_size=64
logging_steps = len(emotions_encoded['train'])
model_name = f'{model_ckpt}_enmotions_ft'
training_args = TrainingArguments(outputs_dir = model_name,
num_train_epoches=4,
learning_rate=2e-5,
per_device_train_batch_size=batch_size,
per_device_eval_batch_size=batch_size,
weight_decay=0.01,
evaluation_strategy="epoch",
disable_tqdem=False,
logging_steps=logging_steps,
#write
push_to_bb=True,
log_level='error')
- trainer默认自动开启torch的多gpu模式
per_device_train_batch用于设置每个gpu的上限- 一般而言,多gpu模式希望多个Gpu的性能尽可能的接近,否则最终多gpu的速度由最慢的gpu决定
- 比如快gpu跑了1个batch需要5s,跑10个batch需要50s,慢的gpu跑1个batch500s,则快的gpu需要等慢gpu跑完1个batch之后才能继续
- 同理
per_device_eval_batch_size类似
learning_rate/weight_decay- 默认使用AdamW的优化算法
from utils import compute_classification_metrics
trainer = Trainer(model=model,
tokenizer=tokenizer,
train_dataset=emotions_encoded['train']
eval_dataset=emotions_encoded['validation'],
args=training_args,
compute_metrics = compute_classification_metrics2
)
trainer.train()
preds_output = trainer.predict(emotions_encoded["validation"])
preds_output
preds_output = traiher.predict(emotions_encoded["validation"])
y_preds = np.argmax(preds_output.prediction,axis=1)
y_true = emotions_encoded['validation']['label']
from utils import plot_confision_matrix
plot_confusion_matrix(y_preds,y_true,labels)
labels
preds_output = traiher.predict(emotions_encoded["test"])
y_preds = np.argmax(preds_output.prediction,axis=1)
y_true = emotions_encoded['test']['label']
plot_confusion_matrix(y_preds,y_true,labels)
result analysis
from torch.nn.functional import cross_entropy
def forward_pass_with_label(batch):
inputs = {k:v.to(device) for k,v in batch.items()
if k in tokenizer.model_input_name}
with torch.no_grad():
output = model(**inputs)
pred_label = torch.argmax(output.logits,axis=1)
loss = cross_entropy(output.logits,batch['label'].to(device),reduction="none")
# Place outputs on CPU for compatibility with other dataset columns
return {"loss":loss.cpu().numpy(),"predicted_label":pred_labels.cpu().numpy()}
emotions_encoded["validation"]=emotions_encoded["valiadtion"].map(forward_pass_with_label,batched=True,batch_size=16)
emotions_encoded["validation"]
valid_df = pd.DataFrame.from_dict({'text':emotions_encoded["validation"]['txet'],
'label':emotions_encoded['validation']['label'].numpu(),
'pred_label':emotions_encoded["validation"]['loss'].numpy()})
valid_df['label']=valid_bf['label'].apply(lamda x:int2str(x))
valid_df['pred_label']=valid_bf['pred_label'].apply(lamada x:int2str(x))
valid_df
valid_df[vlaid_df['label']!=valid_bf['pred_label']].label.value_counts()
#
valid_df.mort_values('loss',ascending=False.head(10))
#mislabeld
valid_df.iloc[882].text
# less loss menas more confident
# sadness/joy
valid_df.sort_value('loss',ascending=True).head(20)
to huggingface hub
trainer.push_to_hub(commit_message="Training compeleted")
from transformers import pipeline
model_id = '.../...'
classifier = pipeline(”text-classification",model=model_id)
custom_tweet = "I saw a movie today and it was really good"
custom_tweet = "I saw a movie today adn it suck"
preds = classifier(custom_tweet,return_all_scores=True)
preds
preds_df = pd.DataFrame(preds[0])
plt.bar(labels,100*pred_df["score"],color='C0')
plt.title(f"{custom_tweet}")