2020年2月

[CLS]:在做分類任務時其最後一層的 repr. 會被視為整個輸入序列的 repr.
[SEP]:有兩個句子的文本會被串接成一個輸入序列,並在兩句之間插入這個 token 以做區隔
[UNK]:沒出現在 BERT 字典裡頭的字會被這個 token 取代
[PAD]:zero padding 遮罩,將長度不一的輸入序列補齊方便做 batch 運算
[MASK]:未知遮罩,僅在預訓練階段會用到

sequence : 一个或两个sentence

pretraining task:
masked language modeling(MLM) : 训练挖空填词
next-sentence prediction(NSP) : 训练判断一句话是否是另一句话的下文
albert 指出 NSP 的结果 unreliable,使用 sentence-order prediction(SOP) 替代 NSP
SOP 将一段打乱的话排序

BERT base : L(层数) 12, H(hidden size) 768, A(attention heads) 12, 总参数量:110M
BERT large : L 24, H 1024, A 16, 总参数量:340M

在 BERT 中 embedding size E 和 hidden size H 始终相等,embedding 层参数数为 V(vocabulary size) * H
在 ALBERT 中将参数数量 reduce 至 V * E + E * H

torch.cuda.is_available() #cuda是否可用
import torch
import torch.nn as nn

class MyModule(nn.Module):
    def __init__(self, <args>):
        super().__init__()
        #初始化
        self.fc = nn.Linear(in, out) 
        self.fc.weight.data.uniform_(-0.5, 0.5)
        self.fc.bias.data.zero_()

    def forward(self, <args>):
        return self.fc()


device = torch.device("cuda")

model = MyModule(<args>).to(device)
criterion = torch.nn.CrossEntropyLoss().to(device)
optimizer = torch.optim.SGD(model.parameters(), lr=4.0)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1, gamma=0.9)

def train(nn, iterator, optimizer, criteon):
    nn.train()
    for i, batch in enumerate(iterator):
        optimizer.zero_grad()
        pred = nn(batch.text)
        loss = criteon(pred, batch.label)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

def eval(nn, iterator, criteon):
    rnn.eval()
    with torch.no_grad():
        for batch in iterator:
            pred = nn(batch.text)
            loss = criteon(pred, batch.label)


变换

torch.triu(tensor) 将 tensor 变为右上三角
tensor.masked_fill(mask, value) 将 mask 为 True 位置用 value 填充
下标索引x::y:从x开始间隔y取一个

操作

model.parameters() : 返回模型所有参数的generator
tensor.numel() :返回模型参数数量

optim

torch.optim.SGD(model.parameters(), lr = 0.01, momentum)

layer

nn.Embedding(vocab_size, embedding_dim)
单词到word vector
vocab_size : 词汇量大小
输入:1维index索引
输出:embedding_dim维word vector

nn.LSTM(embedding_dim, hidden_dim, num_layers = 2)
LSTM层
dropout:默认0
bidirectional:默认False

nn.Linear(in_size, out_size)
全连接层

torch.cat([hidden[-2], hidden[-1]], )

并行

if local_rank != 0:
    torch.distributed.barrier()
# 只有主进程执行
if local_rank == 0:
    torch.distributed.barrier()
#所有进程执行

model = torch.nn.DataParallel(model) #多GPU数据并行
torch.cuda.device_count() #GPU数量
model = torch.nn.DataParallel(model) #多GPU数据并行

input gate

$$i^{(t)} = sigmoid(W^i [h^{(t-1)}, x^{(t)}] + b^i)$$

forget gate

$$f^{(t)}=sigmoid(W^f [h^{(t-1)}, x^{(t)}] + b^f)$$

output gate

$$o^{(t)}=sigmoid(W^o [h^{(t-1)}, x^{(t)}] + b^o)$$

$$\overline{C}^{(t)}=tanh(W^C[h^{(t-1)}, x^{(t)}] + b^C)$$

$$C^{(t)} = f^{(t)}C^{(t-1)} + i^{(t)}\overline{C}^{(t)}$$

$$h^{(t)} = tanh(C^{(t)})\times o^{(t)}$$

#pragma omp simd
for循环前对for循环显式simd优化

#pragma omp declare simd
函数前使函数生成simd版本

#pargma ivdep
for循环前忽略vector dependence

#pargma vector nontemporal
跳过过渡cache,直接stream到最下层cache

#include <omp.h>
int nt = omp_get_max_threads();

omp最多线程数

#pragma omp parallel private(A) share(B)
{
    int C;
    omp_get_thread_num();
}

omp多线程运行
每个thread有独立的A变量,B变量在所有thread间share
每个thread有独立C

export OMP_NUM_THREADS=5
限制omp线程数

fork thread:

#include <pthread.h>
int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,
(void*)(*start_rtn)(void*),void *arg);

fork出一个thread
-lpthread

fork process:

pid = fork();

parent进程pid = 0,child进程pid!=0