国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當前位置: 首頁 > news >正文

做淘寶客網(wǎng)站要備案嗎營銷網(wǎng)站建設都是專業(yè)技術人員

做淘寶客網(wǎng)站要備案嗎,營銷網(wǎng)站建設都是專業(yè)技術人員,新聞列表做的最好的網(wǎng)站,網(wǎng)站如何連接微信支付1、導 讀 2017 年,Google 研究團隊發(fā)表了一篇名為《Attention Is All You Need》的論文,提出了 Transformer 架構,是機器學習,特別是深度學習和自然語言處理領域的范式轉變。 Transformer 具有并行處理功能,可以實現(xiàn)…

1、導 讀

2017 年,Google 研究團隊發(fā)表了一篇名為《Attention Is All You Need》的論文,提出了 Transformer 架構,是機器學習,特別是深度學習和自然語言處理領域的范式轉變。

Transformer 具有并行處理功能,可以實現(xiàn)更高效、可擴展的模型,從而更容易在大型數(shù)據(jù)集上訓練它們。它還在情感分析和文本生成任務等多項 NLP 任務中表現(xiàn)出了卓越的性能。

在本筆記本中,我們將探索 Transformer 架構及其所有組件。我將使用 PyTorch 構建所有必要的結構和塊,并且我將在 PyTorch 上使用從頭開始編Transformer。

#?導入庫#?PyTorch?
import?torch?
import?torch.nn as nn?
from torch.utils.data?import?Dataset,?DataLoader,?random_split?
from torch.utils.tensorboard?import?SummaryWriter?#?Math?
import?math?#?HuggingFace?庫
from datasets?import?load_dataset?
from tokenizers?import?Tokenizer?
from tokenizers?.models?import?WordLevel?
from tokenizers.trainers?import?WordLevelTrainer?
from tokenizers.pre_tokenizers?import?Whitespace?#?Pathlib?
from pathlib?import?Path?#?Typing?
from?Typing?import??Any?#?循環(huán)中進度條的庫
from tqdm?import?tqdm?#?導入警告庫
import?warnings

2、Transformer 架構

在編碼之前,我們先看一下Transformer的架構。

Transformer 架構有兩個主要模塊:編碼器解碼器。讓我們進一步看看它們。

編碼器:它具有多頭注意力機制和全連接的前饋網(wǎng)絡。兩個子層周圍還有殘差連接,以及每個子層輸出的層歸一化。模型中的所有子層和嵌入層都會產(chǎn)生維度?𝑑_𝑚𝑜𝑑𝑒𝑙=512?的輸出。

解碼器:解碼器遵循類似的結構,但它插入了第三個子層,該子層對編碼器塊的輸出執(zhí)行多頭關注。解碼器塊中的自注意子層也進行了修改,以避免位置關注后續(xù)位置。這種掩蔽確保位置?𝑖?的預測僅取決于小于𝑖 的位置處的已知輸出。

編碼器和解碼塊都重復?𝑁?次。在原始論文中,他們定義了𝑁 = 6,我們將在本筆記本中定義類似的值。

3、輸入嵌入

當我們觀察上面的 Transformer 架構圖像時,我們可以看到嵌入代表了兩個塊的第一步。

下面的類InputEmbedding負責將輸入文本轉換為d_model維度的數(shù)值向量。為了防止我們的輸入嵌入變得非常小,我們通過將它們乘以 √𝑑_𝑚𝑜𝑑𝑒𝑙 來對其進行標準化。

在下圖中,我們可以看到嵌入是如何創(chuàng)建的。首先,我們有一個被分成標記的句子——我們稍后將探討標記是什么——。然后,令牌 ID(識別號)被轉換為嵌入,即高維向量。

class?InputEmbeddings(nn.Module):def?__init__(self,?d_model:?int,?vocab_size:?int):super().__init__()self.d_model?=?d_model?#?Dimension?of?vectors?(512)self.vocab_size?=?vocab_size?#?Size?of the vocabularyself.embedding?=?nn.Embedding(vocab_size,?d_model)?#?PyTorch?layer that converts integer indices to dense embeddingsdef?forward(self,?x):return?self.embedding(x)?*?math.sqrt(self.d_model)?#?Normalizing?the variance of the embeddings

4、位置編碼

在原始論文中,作者將位置編碼添加到編碼器和解碼器塊底部的輸入嵌入中,以便模型可以獲得有關序列中標記的相對或絕對位置的一些信息。位置編碼與嵌入具有相同的維度𝑑_模型,因此可以將兩個向量相加,并且我們可以將來自單詞嵌入的語義內容和來自位置編碼的位置信息結合起來。

下面我們將創(chuàng)建一個尺寸為 的PositionalEncoding位置編碼矩陣。我們首先用0填充它。然后,我們將正弦函數(shù)應用于位置編碼矩陣的偶數(shù)索引,而余弦函數(shù)應用于奇數(shù)索引。pe(seq_len, d_model)

我們應用正弦和余弦函數(shù),因為它允許模型根據(jù)序列中其他單詞的位置來確定單詞的位置,因為對于任何固定偏移量𝑃𝐸???????可以表示為𝑃𝐸??? 的線性函數(shù)。發(fā)生這種情況是由于正弦和余弦函數(shù)的特性,其中輸入的變化會導致輸出發(fā)生可預測的變化。

class?PositionalEncoding(nn.Module):def?__init__(self,?d_model:?int,?seq_len:?int,?dropout:?float)?->?None:super().__init__()self.d_model?=?d_model?#?Dimensionality?of the modelself.seq_len?=?seq_len?#?Maximum?sequence lengthself.dropout?=?nn.Dropout(dropout)?#?Dropout?layer to prevent overfitting#?Creating?a positional encoding matrix of?shape?(seq_len,?d_model)?filled with?zerospe?=?torch.zeros(seq_len,?d_model)?#?Creating?a tensor representing?positions?(0?to seq_len?-?1)position?=?torch.arange(0,?seq_len,?dtype?=?torch.float).unsqueeze(1)?#?Transforming?'position'?into a?2D?tensor['seq_len,?1']#?Creating?the division term?for?the positional encoding?formuladiv_term?=?torch.exp(torch.arange(0,?d_model,?2).float()?*?(-math.log(10000.0)?/?d_model))#?Apply?sine to even indices in pepe[:,?0::2]?=?torch.sin(position?*?div_term)#?Apply?cosine to odd indices in pepe[:,?1::2]?=?torch.cos(position?*?div_term)#?Adding?an extra dimension at the beginning of pe matrix?for?batch?handlingpe?=?pe.unsqueeze(0)#?Registering?'pe'?as buffer.?Buffer?is a tensor not considered as a model parameterself.register_buffer('pe',?pe)?def?forward(self,x):#?Addind?positional encoding to the input tensor?Xx?=?x?+?(self.pe[:,?:x.shape[1],?:]).requires_grad_(False)return?self.dropout(x)?#?Dropout?for?regularization

5、層歸一化

當我們查看編碼器和解碼器塊時,我們會看到幾個稱為Add & Norm的歸一化層。

下面的類LayerNormalization對輸入數(shù)據(jù)執(zhí)行層歸一化。在前向傳播過程中,我們計算輸入數(shù)據(jù)的平均值和標準差。然后,我們通過減去平均值并除以標準差加上一個稱為epsilon的小數(shù)來標準化輸入數(shù)據(jù),以避免被零除。此過程會產(chǎn)生平均值為 0、標準差為 1 的標準化輸出。

然后,我們將通過可學習參數(shù)縮放標準化輸出alpha,并添加一個名為 的可學習參數(shù)bias。訓練過程負責調整這些參數(shù)。最終結果是層歸一化張量,它確保網(wǎng)絡中各層的輸入規(guī)模一致。

#?Creating?Layer?Normalization
class?LayerNormalization(nn.Module):def?__init__(self,?eps:?float?=?10**-6)?->?None:?#?We?define epsilon as?0.000001?to avoid division by zerosuper().__init__()self.eps?=?eps#?We?define alpha as a trainable parameter and initialize it with onesself.alpha?=?nn.Parameter(torch.ones(1))?#?One-dimensional tensor that will be used to scale the input data#?We?define bias as a trainable parameter and initialize it with zerosself.bias?=?nn.Parameter(torch.zeros(1))?#?One-dimensional tenso that will be added to the input datadef?forward(self,?x):mean?=?x.mean(dim?=?-1,?keepdim?=?True)?#?Computing?the mean of the input data.?Keeping?the number of dimensions?unchangedstd?=?x.std(dim?=?-1,?keepdim?=?True)?#?Computing?the standard deviation of the input data.?Keeping?the number of dimensions unchanged#?Returning?the normalized inputreturn?self.alpha?*?(x-mean)?/?(std?+?self.eps)?+?self.bias

6、前饋網(wǎng)絡

在全連接前饋網(wǎng)絡中,我們應用兩個線性變換,并在其間使用 ReLU 激活。我們可以用數(shù)學方式將該操作表示為:

W1 和W2?是權重,而b1 和b2?是兩個線性變換的偏差。

下面FeedForwardBlock,我們將定義兩個線性變換 -self.linear_1self.linear_2- 以及內層d_ff。輸入數(shù)據(jù)將首先經(jīng)過self.linear_1轉換,將其維度從d_model增加到d_ff

此操作的輸出通過 ReLU 激活函數(shù),該函數(shù)引入了非線性,因此網(wǎng)絡可以學習更復雜的模式,并且該self.dropout層用于減輕過度擬合。最后的操作是self.linear_2轉換為 dropout-modified 張量,將其轉換回原始d_model維度。

#?創(chuàng)建前饋層
class?FeedForwardBlock(nn.Module):def?__init__(self,?d_model:?int,?d_ff:?int,?dropout:?float)?->?None:super().__init__()#?第一次線性變換self.linear_1?=?nn.Linear(d_model,?d_ff)?#?W1?&?b1self.dropout?=?nn.Dropout(dropout)?#?Dropout?to prevent overfitting#?第二次線性變換self.linear_2?=?nn.Linear(d_ff,?d_model)?#?W2?&?b2def?forward(self,?x):#?(Batch,?seq_len,?d_model)?-->?(batch,?seq_len,?d_ff)?-->(batch,?seq_len,?d_model)return?self.linear_2(self.dropout(torch.relu(self.linear_1(x))))

7、多頭注意力

多頭注意力是 Transformer 最關鍵的組成部分。它負責幫助模型理解數(shù)據(jù)中的復雜關系和模式。

下圖顯示了多頭注意力機制的工作原理。它不包括batch維度,因為它僅說明一個句子的過程。

多頭注意力模塊接收分為查詢、鍵和值的輸入數(shù)據(jù),并組織成矩陣𝑄、𝐾𝑉。每個矩陣包含輸入的不同方面,并且它們具有與輸入相同的維度。

然后,我們通過各自的權重矩陣𝑊^Q、𝑊^K𝑊^V來對每個矩陣進行線性變換。這些轉換將產(chǎn)生新的矩陣𝑄′、𝐾′𝑉′,它們將被分成與不同頭?相對應的更小的矩陣,從而允許模型并行處理來自不同表示子空間的信息。這種分割為每個頭創(chuàng)建多組查詢、鍵和值。

最后,我們將每個頭連接成一個𝐻矩陣,然后由另一個權重矩陣𝑊𝑜進行轉換以產(chǎn)生多頭注意力輸出,即保留輸入維度的矩陣𝑀𝐻?𝐴 。

#?創(chuàng)建多頭注意力區(qū)塊
class?MultiHeadAttentionBlock(nn.Module):def?__init__(self,?d_model:?int,?h:?int,?dropout:?float)?->?None:?#?h?=?number of headssuper().__init__()self.d_model?=?d_modelself.h?=?h#?我們確保模型的維度可以被頭的數(shù)量整除assert?d_model?%?h?==?0,?'d_model is not divisible by h'#?d_k?是每個注意力的維度head?的鍵、查詢和值向量self.d_k?=?d_model?//?h?#?d_k?公式,就像原始的“Attention Is All You Need”論文中一樣#?定義權重矩陣self.w_q?=?nn.Linear(d_model,?d_model)?#?W_qself.w_k?=?nn.Linear(d_model,?d_model)?#?W_kself.w_v?=?nn.Linear(d_model,?d_model)?#?W_vself.w_o?=?nn.Linear(d_model,?d_model)?#?W_oself.dropout?=?nn.Dropout(dropout)?#?Dropout?層以避免過度擬合@staticmethoddef?attention(query,?key,?value,?mask,?dropout:?nn.Dropout):#?mask?=>?當我們希望某些單詞不與其他單詞交互時,我們“隱藏”它們d_k?=?query.shape[-1]?#?查詢、鍵和值的最后一個維度#?我們按照上圖中的公式計算?Attention(Q,K,V)?attention_scores?=?(query?@?key.transpose(-2,-1))?/?math.sqrt(d_k)?#?@?=?Matrix?multiplication sign in?PyTorch#?在應用?softmax?之前,我們應用掩碼來隱藏單詞之間的一些交互if?mask is not?None:?#?如果定義了掩碼..?.attention_scores.masked_fill_(mask?==?0,?-1e9)?#?將?mask?等于?0?的每個值替換為?-1e9attention_scores?=?attention_scores.softmax(dim?=?-1)?if?dropout is not?None:?attention_scores?=?dropout(attention_scores)?#?我們使用?dropout?來防止過擬合return?(attention_scores?@?value),?attention_scores?#?將輸出矩陣乘以?V?矩陣,公式如下def?forward(self,?q,?k,?v,?mask):??query?=?self.w_q(q)?#?Q'?matrixkey?=?self.w_k(k)?#?K'?matrixvalue?=?self.w_v(v)?#?V'?matrix#?將結果拆分為不同頭的較小矩陣#?將嵌入(第三維)拆分為?h?個部分query?=?query.view(query.shape[0],?query.shape[1],?self.h,?self.d_k).transpose(1,2)?#?Transpose?=>?將頭部帶到第二個維度key?=?key.view(key.shape[0],?key.shape[1],?self.h,?self.d_k).transpose(1,2)?#?Transpose?=>?將頭部帶到第二個維度value?=?value.view(value.shape[0],?value.shape[1],?self.h,?self.d_k).transpose(1,2)?#?Transpose?=>?將頭部帶到第二個維度#?獲取輸出和注意力分數(shù)x,?self.attention_scores?=?MultiHeadAttentionBlock.attention(query,?key,?value,?mask,?self.dropout)#?獲取H矩陣x?=?x.transpose(1,?2).contiguous().view(x.shape[0],?-1,?self.h?*?self.d_k)return?self.w_o(x)?#?Multiply?the H matrix by the weight matrix W_o,?resulting in the MH-A matrix

8、剩余連接

當我們查看 Transformer 的架構時,我們看到每個子層(包括自注意力前饋塊)在將其傳遞到Add & Norm層之前將其輸出添加到輸入。此方法將輸出與Add & Norm層中的原始輸入集成。這個過程稱為跳躍連接,它允許 Transformer 通過為反向傳播期間梯度流經(jīng)提供捷徑來更有效地訓練深度網(wǎng)絡。

下面的類ResidualConnection負責這個過程。

#?構建剩余連接
class?ResidualConnection(nn.Module):def?__init__(self,?dropout:?float)?->?None:super().__init__()self.dropout?=?nn.Dropout(dropout)?#?我們使用?dropout?層來防止過度擬合self.norm?=?LayerNormalization()?#?我們使用歸一化層def?forward(self,?x,?sublayer):#?我們對輸入進行歸一化并將其添加到原始輸入“x”。這將創(chuàng)建剩余連接過程。return?x?+?self.dropout(sublayer(self.norm(x)))?

9、編碼器

我們現(xiàn)在將構建編碼器。我們創(chuàng)建的EncoderBlock類由多頭注意力層和前饋層以及殘差連接組成。

在原始論文中,編碼器塊重復六次。我們將Encoder類創(chuàng)建為多個 s 的集合EncoderBlock。在通過其所有塊處理輸入之后,我們還添加層歸一化作為最后一步。

#?構建編碼器模塊
class?EncoderBlock(nn.Module):#?該程序塊接收多頭注意程序塊和前饋程序塊,以及剩余連接的中斷率def?__init__(self,?self_attention_block:?MultiHeadAttentionBlock,?feed_forward_block:?FeedForwardBlock,?dropout:?float)?->?None:super().__init__()#?存儲自我注意區(qū)塊和前饋區(qū)塊self.self_attention_block?=?self_attention_blockself.feed_forward_block?=?feed_forward_blockself.residual_connections?=?nn.ModuleList([ResidualConnection(dropout)?for?_ in?range(2)])?def?forward(self,?x,?src_mask):#?將第一個殘余連接應用于自我關注區(qū)塊x?=?self.residual_connections[0](x,?lambda x:?self.self_attention_block(x,?x,?x,?src_mask))?#?三個?"x?"分別對應查詢、鍵和值輸入以及源掩碼#?將第二個殘差連接應用于前饋區(qū)塊x?=?self.residual_connections[1](x,?self.feed_forward_block)return?x?
#?建設編碼器
#?一個編碼器可以有多個編碼器模塊
class?Encoder(nn.Module):#?編碼器接收?"EncoderBlock?"實例def?__init__(self,?layers:?nn.ModuleList)?->?None:super().__init__()self.layers?=?layers?#?存儲編碼器塊self.norm?=?LayerNormalization()?#?編碼器層輸出標準化層def?forward(self,?x,?mask):#?遍歷存儲在?self.layers?中的每個編碼器塊for?layer in self.layers:x?=?layer(x,?mask)?#?對輸入張量?"x?"應用每個編碼器塊return?self.norm(x)?

10、解碼器

類似地,Decoder 也由幾個 DecoderBlock 組成,在原論文中重復了六次。主要區(qū)別在于它有一個額外的子層,該子層通過交叉注意組件執(zhí)行多頭注意,該交叉注意組件使用編碼器的輸出作為其鍵和值,同時使用解碼器的輸入作為查詢。

對于輸出嵌入,我們可以使用InputEmbeddings與編碼器相同的類。您還可以注意到,自注意力子層被屏蔽,這限制了模型訪問序列中的未來元素。

我們將從構建類開始DecoderBlock,然后構建類Decoder,它將組裝多個DecoderBlocks。

#?構建解碼器模塊
class?DecoderBlock(nn.Module):#?解碼器模塊接收兩個多頭注意力模塊。一個是自注意,另一個是交叉注意。def?__init__(self,??self_attention_block:?MultiHeadAttentionBlock,?cross_attention_block:?MultiHeadAttentionBlock,?feed_forward_block:?FeedForwardBlock,?dropout:?float)?->?None:super().__init__()self.self_attention_block?=?self_attention_blockself.cross_attention_block?=?cross_attention_blockself.feed_forward_block?=?feed_forward_blockself.residual_connections?=?nn.ModuleList([ResidualConnection(dropout)?for?_ in?range(3)])?def?forward(self,?x,?encoder_output,?src_mask,?tgt_mask):#?包含查詢、關鍵字和值以及目標語言掩碼的自關注塊x?=?self.residual_connections[0](x,?lambda x:?self.self_attention_block(x,?x,?x,?tgt_mask))#?交叉注意代碼塊使用兩個?"encoder_ouput?"來輸入鍵和值,再加上源語言掩碼。它還接收用于解碼器查詢的'x'。x?=?self.residual_connections[1](x,?lambda x:?self.cross_attention_block(x,?encoder_output,?encoder_output,?src_mask))#?帶有殘余連接的前饋區(qū)塊x?=?self.residual_connections[2](x,?self.feed_forward_block)return?x
#?構建解碼器
#?一個解碼器可以有多個解碼塊
class?Decoder(nn.Module):#?解碼器接收?"DecoderBlock?"的實例def?__init__(self,?layers:?nn.ModuleList)?->?None:super().__init__()self.layers?=?layersself.norm?=?LayerNormalization()?def?forward(self,?x,?encoder_output,?src_mask,?tgt_mask):for?layer in self.layers:x?=?layer(x,?encoder_output,?src_mask,?tgt_mask)return?self.norm(x)

可以在解碼器圖像中看到,在運行一堆DecoderBlocks 后,我們有一個線性層和一個 Softmax 函數(shù)來輸出概率。下面的類ProjectionLayer負責將模型的輸出轉換為詞匯表上的概率分布,其中我們從可能的標記詞匯表中選擇每個輸出標記。

#?建立線性層
class?ProjectionLayer(nn.Module):def?__init__(self,?d_model:?int,?vocab_size:?int)?->?None:?super().__init__()self.proj?=?nn.Linear(d_model,?vocab_size)?def?forward(self,?x):return?torch.log_softmax(self.proj(x),?dim?=?-1)?

11、構建Transformer

現(xiàn)在可以通過將它們放在一起來構建 Transformer。

#?創(chuàng)建?Transformer?結構
class?Transformer(nn.Module):def?__init__(self,?encoder:?Encoder,?decoder:?Decoder,?src_embed:?InputEmbeddings,?tgt_embed:?InputEmbeddings,?src_pos:?PositionalEncoding,?tgt_pos:?PositionalEncoding,?projection_layer:?ProjectionLayer)?->?None:super().__init__()self.encoder?=?encoderself.decoder?=?decoderself.src_embed?=?src_embedself.tgt_embed?=?tgt_embedself.src_pos?=?src_posself.tgt_pos?=?tgt_posself.projection_layer?=?projection_layer#?Encoder?????def?encode(self,?src,?src_mask):src?=?self.src_embed(src)?#?Applying?source embeddings to the input source?languagesrc?=?self.src_pos(src)?#?Applying?source positional encoding to the source embeddingsreturn?self.encoder(src,?src_mask)?#?Returning?the source embeddings plus a source mask to prevent attention to certain elements#?Decoderdef?decode(self,?encoder_output,?src_mask,?tgt,?tgt_mask):tgt?=?self.tgt_embed(tgt)?#?Applying?target embeddings to the input target?language?(tgt)tgt?=?self.tgt_pos(tgt)?#?Applying?target positional encoding to the target embeddingsreturn?self.decoder(tgt,?encoder_output,?src_mask,?tgt_mask)def?project(self,?x):return?self.projection_layer(x)

我們現(xiàn)在定義一個名為 的函數(shù),在其中定義參數(shù)以及為機器翻譯build_transformer任務建立一個完全可操作的 Transformer 模型所需的一切。

我們將設置與原始論文Attention Is All You Need中相同的參數(shù),其中𝑑_𝑚𝑜𝑑𝑒𝑙 = 512、𝑁 = 6? = 8、dropout 率𝑃_𝑑𝑟𝑜𝑝 = 0.1𝑑_𝑓𝑓= 2048?.

12、分詞器

標記化是我們 Transformer 模型的關鍵預處理步驟。在此步驟中,我們將原始文本轉換為模型可以處理的數(shù)字格式。

有多種代幣化策略。我們將使用單詞級標記化將句子中的每個單詞轉換為標記。

對句子進行分詞后,我們根據(jù)分詞器訓練期間訓練語料庫中存在的創(chuàng)建詞匯將每個分詞映射到唯一的整數(shù) ID。每個整數(shù)代表詞匯表中的一個特定單詞。

除了訓練語料庫中的單詞外,Transformer 還使用特殊標記來實現(xiàn)特定目的。我們將立即定義以下一些內容:

? [UNK]:該標記用于識別序列中的未知單詞。

? [PAD]:填充標記以確保批次中的所有序列具有相同的長度,因此我們用此標記填充較短的句子。我們使用注意力掩碼“告訴”模型在訓練期間忽略填充的標記,因為它們對任務沒有任何實際意義。

? [SOS]:這是一個用于表示句子開始的標記。

? [EOS]:這是一個用于表示句子結束的標記。

build_tokenizer下面的函數(shù)中,我們確保標記器已準備好訓練模型。它檢查是否存在現(xiàn)有的分詞器,如果不存在,則訓練新的分詞器。

def?build_tokenizer(config,?ds,?lang):tokenizer_path?=?Path(config['tokenizer_file'].format(lang))if?not?Path.exists(tokenizer_path):?tokenizer?=?Tokenizer(WordLevel(unk_token?=?'[UNK]'))?#?Initializing?a?new?world-level tokenizertokenizer.pre_tokenizer?=?Whitespace()?#?We?will split the text into tokens based on?whitespacetrainer?=?WordLevelTrainer(special_tokens?=?["[UNK]",?"[PAD]",?"[SOS]",?"[EOS]"],?min_frequency?=?2)?tokenizer.train_from_iterator(get_all_sentences(ds,?lang),?trainer?=?trainer)tokenizer.save(str(tokenizer_path))?#?Saving?trained tokenizer to the file path specified at the beginning of the functionelse:tokenizer?=?Tokenizer.from_file(str(tokenizer_path))?#?If?the tokenizer already exist,?we load itreturn?tokenizer?#?Returns?the loaded tokenizer or the trained tokenizer
http://aloenet.com.cn/news/39187.html

相關文章:

  • 個人網(wǎng)站建設策劃書百度推廣后臺
  • 家裝業(yè)務員怎么做網(wǎng)站營銷網(wǎng)絡廣告有哪些形式
  • 嘉興營銷型網(wǎng)站上海網(wǎng)絡推廣優(yōu)化公司
  • 高端網(wǎng)站開發(fā)建設網(wǎng)站媒體推廣
  • 做數(shù)據(jù)網(wǎng)站手機百度如何發(fā)布作品
  • 怎么用自己電腦做網(wǎng)站服務器嗎企業(yè)網(wǎng)站設計與實現(xiàn)論文
  • avada做網(wǎng)站seo公司北京
  • 做啤酒行業(yè)的網(wǎng)站公司網(wǎng)站建設流程
  • 網(wǎng)站開發(fā)需求描述seo站
  • 怎么做網(wǎng)站在里面填字qq群推廣網(wǎng)站免費
  • 怎樣做1個網(wǎng)站搜索引擎搜索器
  • 站長工具推薦代寫軟文
  • 做設計靈感的網(wǎng)站seo團隊
  • 鄭州網(wǎng)站建設程序網(wǎng)站頁面禁止訪問
  • 公司的企業(yè)文化怎么寫微信搜一搜seo
  • 做的好的微信商城網(wǎng)站什么是seo推廣
  • 網(wǎng)站的后臺是開發(fā)做的八零云自助建站免費建站平臺
  • 做網(wǎng)站python和php哪個好學百度推廣怎么弄
  • 深圳 汽車網(wǎng)站建設百度網(wǎng)站首頁提交入口
  • seo診斷服務優(yōu)化什么
  • 中國哪些網(wǎng)站做軟裝seo廠商
  • 四川疫情最新消息今天優(yōu)化服務
  • 網(wǎng)站設計建設定制中國搜索引擎市場份額
  • 網(wǎng)站建設策劃方案如何寫愛站網(wǎng)關鍵詞查詢網(wǎng)站的工具
  • 新媒體營銷策略有哪些百度推廣優(yōu)化中心
  • 備案通過后 添加網(wǎng)站谷歌瀏覽器下載手機版安卓
  • 網(wǎng)站界面用什么做廈門百度推廣排名優(yōu)化
  • 高端的網(wǎng)站建設百度seo有用嗎
  • 造價咨詢公司加盟分公司上海百度搜索排名優(yōu)化
  • 鄭州企業(yè)建站模板河南疫情最新消息