| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- from torch import nn
- import math
- import torch
- # embedding层
- class Embeddings(nn.Module):
- def __init__(self, vocab_size,d_model):
- super().__init__()
- self.lut = nn.Embedding(vocab_size,d_model)
- self.d_model = d_model
-
- def forward(self,x):
- return self.lut(x) * math.sqrt(self.d_model)
- # 位置编码层
- class PositionalEncoding(nn.Module):
- def __init__(self, d_model,max_len=5000,dropout=0.1) -> None:
- super().__init__()
- self.dropout = nn.Dropout(dropout)
-
- pe = torch.zeros(max_len,d_model)
-
- position = torch.arange(0,max_len).unsqueeze(1)
- div_term = torch.exp(torch.arange(0,d_model,2) * -math.log(1000) / d_model)
-
- pe[:,0::2] = torch.sin(position * div_term)
- pe[:,1::2] = torch.cos(position * div_term)
- pe = pe.unsqueeze(0)
- self.register_buffer("pe",pe)
-
- def forward(self,x):
- x = x+ self.pe[:,:x.size(1)]
- return self.dropout(x)
- #注意力机制增加掩码
- def get_padding_mask(x,padding_idx):
- return (x == padding_idx).unsqueeze(1)
- #注意力机制
- def attention(q,k,v,mask=None,dropout=None):
- d_k = k.size(-1)
- scores = torch.matmul(q,k.transpose(-2,-1)) / math.sqrt(d_k)
- if mask is not None:
- scores = scores.masked_fill(mask,-1e9)
- p_attn = torch.softmax(scores,dim=-1)
- if dropout is not None:
- p_attn = dropout(p_attn)
- return torch.matmul(p_attn,v)
- #多头注意力机制
- class MultiHeadedAttention(nn.Module):
- def __init__(self, d_model,n_head,dropout=0.1):
- super().__init__()
- self.dropout = nn.Dropout(dropout)
-
- #必须能被整除
- assert d_model % n_head == 0
- self.d_k = d_model // n_head
- self.n_head = n_head
-
- #
- self.W_Q = nn.Linear(d_model,d_model,bias=False)
- self.W_K = nn.Linear(d_model,d_model,bias=False)
- self.W_V = nn.Linear(d_model,d_model,bias=False)
-
- self.linear = nn.Linear(d_model,d_model,bias=False)
- #norm
- self.norm = nn.LayerNorm(d_model)
- def forward(self,q,k,v,mask=None):
- res = q
- #分头
- #shape batch_size,seq_len,d_mdoel
- q = self.W_Q(q).view(q.shape[0],q.shape[1],self.n_head,self.d_k).transpose(1,2)
- k = self.W_K(k).view(k.shape[0],k.shape[1],self.n_head,self.d_k).transpose(1,2)
- v = self.W_V(v).view(v.shape[0],v.shape[1],self.n_head,self.d_k).transpose(1,2)
-
- #掩码也需要升维
- if mask is not None:
- mask = mask.unsqueeze(1)
- #计算注意力
- context = attention(q,k,v,mask,self.dropout)
- #拼接
- concat = context.transpose(1,2).reshape(q.shape[0],-1,self.n_head * self.d_k)
- output = self.linear(concat)
- return self.norm(res+output)
- #前馈神经网络
- class FeedForwardNet(nn.Module):
- def __init__(self, d_model, d_ff, dropout=0.1):
- super().__init__()
- self.dropout = nn.Dropout(dropout)
- self.w1 = nn.Linear(d_model, d_ff)
- self.w2 = nn.Linear(d_ff, d_model)
- # self.relu = nn.ReLU()
- self.gelu = nn.GELU() # GELU 不会像 ReLU 那样简单地把所有负数都设置为 0,而是进行更平滑的处理
- self.norm = nn.LayerNorm(d_model) # 对每个token的 d_model 个特征进行归一化,有助于训练稳定
- def forward(self, x):
- res = x
- # x = self.relu(self.w1(x))
- x = self.gelu(self.w1(x)) # 执行顺序由内向外
- x = self.dropout(self.w2(x))
- return self.norm(x + res)
- #编码器子层
- class EncoderLayer(nn.Module):
- def __init__(self,d_model,n_head,d_ff,dropout=0.1):
- super().__init__()
- self.mha=MultiHeadedAttention(d_model,n_head,dropout)
- self.ffn=FeedForwardNet(d_model,d_ff,dropout)
-
- def forward(self,x,mask=None):
- output = self.mha(x,x,x,mask)
- return self.ffn(output)
- #编码器层
- class Encoder(nn.Module):
- def __init__(self,vocab_size,d_model,n_head,d_ff,N=6,dropout=0.1):
- super().__init__()
- self.emb = Embeddings(vocab_size,d_model)
- self.pos = PositionalEncoding(d_model=d_model,dropout=dropout)
- self.layers = nn.ModuleList([
- EncoderLayer(d_model,n_head,d_ff,dropout)
- for _ in range(N)
- ])
-
-
- def forward(self,x,mask=None):
- x = self.emb(x)
- x = self.pos(x)
- for layer in self.layers:
- x = layer(x,mask)
- return x
- #生成掩码
- def get_subsequent_mask(size):
- mask_shape=(1,size,size)
- return 1-torch.tril(torch.ones(mask_shape)).byte()
- #解码器层
- class DecoderLayer(nn.Module):
- def __init__(self,d_model,n_head,d_ff,dropout=0.1):
- super().__init__()
- self.self_mha = MultiHeadedAttention(d_model,n_head,dropout)
- self.mha = MultiHeadedAttention(d_model,n_head,dropout)
- self.ffn = FeedForwardNet(d_model,d_ff,dropout)
-
- def forward(self,x,mask,memory,src_mask):
- x = self.self_mha(x,x,x,mask)
- x = self.mha(x,memory,memory,src_mask)
- return self.ffn(x)
- #
- class Decoder(nn.Module):
- def __init__(self,vocab_size,d_model,n_head,d_ff,N=6,dropout=0.1):
- super().__init__()
- self.emb = Embeddings(vocab_size,d_model)
- self.pos = PositionalEncoding(d_model=d_model,dropout=dropout)
- self.layers = nn.ModuleList([
- DecoderLayer(d_model,n_head,d_ff,dropout)
- for _ in range(N)
- ])
-
- def forward(self,x,mask,memory,src_mask):
- x =self.emb(x)
- x =self.pos(x)
- for layer in self.layers:
- x = layer(x,mask,memory,src_mask)
- return x
- #生成器
- class Generator(nn.Module):
- def __init__(self,d_model,vocab_size):
- super().__init__()
- self.linear = nn.Linear(d_model,vocab_size)
- def forward(self,x):
- return self.linear(x)
- #return torch.softmax(self.linear(x),dim=-1)
- #模型封装
- class Transformer(nn.Module):
- def __init__(self, src_vocab_size, tgt_vocab_size, d_model, n_head, d_ff, N=6, dropout=0.1):
- super().__init__()
- self.encoder = Encoder(src_vocab_size, d_model, n_head, d_ff, N, dropout)
- self.decoder = Decoder(tgt_vocab_size, d_model, n_head, d_ff, N, dropout)
- self.generator = Generator(d_model, tgt_vocab_size)
- def forward(self, src_x, src_mask, tgt_x, tgt_mask):
- memory = self.encoder(src_x, src_mask)
- output = self.decoder(tgt_x, tgt_mask, memory, src_mask)
- return self.generator(output)
- def make_model(src_vocab_size, tgt_vocab_size, d_model, n_head, d_ff, N=6, dropout=0.1):
- model = Transformer(src_vocab_size, tgt_vocab_size, d_model, n_head, d_ff, N, dropout)
- for p in model.parameters():
- if p.dim() > 1:
- nn.init.xavier_uniform_(p)
- return model
- if __name__ == '__main__':
- src_vocab_size = 10
- tgt_vocab_size = 20
- d_model = 8
- n_head = 2
- d_ff = 2048
- N = 6
- dropout = 0.1
- model = make_model(src_vocab_size, tgt_vocab_size, d_model, n_head, d_ff, N, dropout)
- print(model)
- # 输入数据
- src_inputs = torch.tensor([
- [1, 2, 3],
- [4, 5, 0],
- ])
- src_mask = get_padding_mask(src_inputs, 0)
- tgt_inputs = torch.tensor([
- [1, 2, 3, 4],
- [4, 5, 1, 0],
- ])
- # 处理mask
- tgt_pad_mask = get_padding_mask(tgt_inputs, 0)
- subsequent_mask = get_subsequent_mask(4)
- tgt_mask = tgt_pad_mask | subsequent_mask
- tgt_mask = tgt_mask != 0
- predict = model(src_inputs, src_mask, tgt_inputs, tgt_mask)
- print(predict.shape)
|