Transformers and the Quest for HumanLike Language Understanding

1.背景介紹

自然語言處理(NLP)是人工智能領(lǐng)域的一個重要分支,其目標(biāo)是讓計算機理解、生成和處理人類語言。在過去的幾年里,深度學(xué)習(xí)技術(shù)取得了顯著的進展,特別是自注意力機制的出現(xiàn),使得NLP的表現(xiàn)得更加出色。在2017年,Vaswani等人提出了一種新的神經(jīng)網(wǎng)絡(luò)架構(gòu)——Transformer,它在自注意力機制的基礎(chǔ)上進行了擴展和優(yōu)化,從而為NLP帶來了革命性的改變。

在本文中,我們將深入探討Transformer的核心概念、算法原理以及實際應(yīng)用。我們還將討論Transformer在NLP領(lǐng)域的未來發(fā)展趨勢和挑戰(zhàn)。

2.核心概念與聯(lián)系

2.1 Transformer的基本結(jié)構(gòu)

Transformer是一種基于自注意力機制的序列到序列模型,其主要包括以下幾個組件:

  • Multi-Head Self-Attention:這是Transformer的核心組件,它允許模型同時考慮序列中的多個位置。具體來說,它通過多個獨立的注意力頭來進行并行計算,每個頭都專注于不同的信息。

  • Position-wise Feed-Forward Networks:這是Transformer中的另一個關(guān)鍵組件,它是一個普通的前饋神經(jīng)網(wǎng)絡(luò),用于每個位置的輸入。通常,這些網(wǎng)絡(luò)具有相同的結(jié)構(gòu),只是權(quán)重不同。

  • Encoder-Decoder Architecture:Transformer使用了一個編碼器-解碼器架構(gòu),編碼器負責(zé)將輸入序列編碼為隱藏表示,解碼器則將這些隱藏表示解碼為輸出序列。

2.2 Transformer與RNN和LSTM的區(qū)別

與傳統(tǒng)的循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)和長短期記憶網(wǎng)絡(luò)(LSTM)不同,Transformer沒有隱藏狀態(tài)。相反,它使用了自注意力機制來捕捉序列中的長距離依賴關(guān)系。這使得Transformer在處理長序列時具有更好的性能。

3.核心算法原理和具體操作步驟以及數(shù)學(xué)模型公式詳細講解

3.1 Multi-Head Self-Attention

Multi-Head Self-Attention是Transformer的核心組件,它可以計算輸入序列中每個詞的關(guān)注度。關(guān)注度是一個數(shù)值,表示詞與其他詞之間的相似性。關(guān)注度可以通過計算詞間的相似性得到,常用的相似性計算方法有歐幾里得距離、余弦相似度等。

Multi-Head Self-Attention可以看作是多個單頭自注意力的并行計算。每個單頭自注意力都會對輸入序列中的一個子集進行關(guān)注。通過將多個單頭自注意力的結(jié)果進行concatenation(拼接),我們可以得到一個更加豐富的關(guān)注表示。

3.1.1 數(shù)學(xué)模型公式

給定一個輸入序列X \in \mathbb{R}^{n \times d},其中n是序列長度,d是詞向量維度。我們首先將輸入序列通過一個線性層映射為查詢Q \in \mathbb{R}^{n \times d}、鍵K \in \mathbb{R}^{n \times d}和值V \in \mathbb{R}^{n \times d}

Q = XW^Q, \ K = XW^K, \ V = XW^V

其中W^Q, \ W^K, \ W^V \in \mathbb{R}^{d \times d}是可學(xué)習(xí)參數(shù)。

接下來,我們計算每個詞的關(guān)注度A \in \mathbb{R}^{n \times n}

A_{i,j} = \text{softmax}\left(\frac{Q_iK_j^T}{\sqrtu0z1t8os}\right)V_j

其中i, j \in \{1, 2, \dots, n\}。

3.1.2 實際應(yīng)用

在實際應(yīng)用中,我們可以使用PyTorch實現(xiàn)Multi-Head Self-Attention:

import torch
import torch.nn as nn

class MultiHeadAttention(nn.Module):
    def __init__(self, embed_dim, num_heads):
        super(MultiHeadAttention, self).__init__()
        self.embed_dim = embed_dim
        self.num_heads = num_heads
        self.scaling = torch.sqrt(torch.tensor(embed_dim))

    def forward(self, Q, K, V, attn_mask=None):
        # Compute the attention scores
        scores = torch.matmul(Q, K.transpose(-2, -1)) \
                 / self.scaling.expand_as(Q) \
                 .exp()

        # Apply the attention mask if provided
        if attn_mask is not None:
            scores = scores.masked_fill(attn_mask.bool(), -1e9)

        # Compute the attention weights
        p_attn = scores.softmax(dim=-1)

        # Compute the weighted sum of the value vectors
        output = torch.matmul(p_attn, V)

        return output, p_attn

3.2 Position-wise Feed-Forward Networks

Position-wise Feed-Forward Networks(FFN)是Transformer中的另一個關(guān)鍵組件,它是一個普通的前饋神經(jīng)網(wǎng)絡(luò),用于每個位置的輸入。FFN通常具有相同的結(jié)構(gòu),只是權(quán)重不同。

3.2.1 數(shù)學(xué)模型公式

FFN的結(jié)構(gòu)如下:

F(x) = \text{LayerNorm}(x + \text{FFN}(x))

其中F(x)是輸入x經(jīng)過FFN后的結(jié)果,\text{LayerNorm}是層ORMALIZATION操作。FFN的結(jié)構(gòu)如下:

\text{FFN}(x) = \text{Linear}(x) \cdot \text{ReLU}(x) + x

其中\text{Linear}(x)是一個線性層,\text{ReLU}(x)是ReLU激活函數(shù)。

3.2.2 實際應(yīng)用

在實際應(yīng)用中,我們可以使用PyTorch實現(xiàn)Position-wise Feed-Forward Networks:

import torch
import torch.nn as nn

class PositionwiseFeedForward(nn.Module):
    def __init__(self, embed_dim, feedforward_dim):
        super(PositionwiseFeedForward, self).__init__()
        self.linear1 = nn.Linear(embed_dim, feedforward_dim)
        self.linear2 = nn.Linear(feedforward_dim, embed_dim)

    def forward(self, x):
        return self.linear2(torch.relu(self.linear1(x))) + x

3.3 Encoder-Decoder Architecture

Transformer使用了一個編碼器-解碼器架構(gòu),編碼器負責(zé)將輸入序列編碼為隱藏表示,解碼器則將這些隱藏表示解碼為輸出序列。

3.3.1 數(shù)學(xué)模型公式

給定一個輸入序列X \in \mathbb{R}^{n \times d},我們首先使用編碼器E將其編碼為隱藏表示H \in \mathbb{R}^{n \times d}

H = E(X)

接下來,我們使用解碼器D將隱藏表示H解碼為輸出序列Y \in \mathbb{R}^{n \times d}

Y = D(H)

3.3.2 實際應(yīng)用

在實際應(yīng)用中,我們可以使用PyTorch實現(xiàn)Encoder-Decoder架構(gòu):

import torch
import torch.nn as nn

class Encoder(nn.Module):
    def __init__(self, embed_dim, num_layers, num_heads, num_pos, num_tokens):
        super(Encoder, self).__init__()
        self.embed_dim = embed_dim
        self.num_layers = num_layers
        self.num_heads = num_heads
        self.num_pos = num_pos
        self.num_tokens = num_tokens

        self.pos_embed = nn.Parameter(torch.zeros(1, num_pos + 1, embed_dim))
        self.token_embed = nn.Embedding(num_tokens, embed_dim)
        self.layernorm1 = nn.LayerNorm(embed_dim)
        self.layernorm2 = nn.LayerNorm(embed_dim)
        self.dropout = nn.Dropout(0.1)

        self.transformer_layers = nn.ModuleList([
            nn.ModuleList([
                nn.ModuleList([
                    MultiHeadAttention(embed_dim, num_heads)
                    for _ in range(num_layers)
                ]) for _ in range(2)
            ]) for _ in range(num_layers)
        ])

    def forward(self, src):
        src_len = src.size(1)
        src = src * 1e-4
        src = src + self.pos_embed
        src = self.token_embed(src)
        src = self.layernorm1(src)

        attn_mask = None
        if self.num_pos > 0:
            attn_mask = torch.zeros((src_len, src_len), device=src.device)
            attn_mask = attn_mask.wonil()
            attn_mask = attn_mask.to(src.dtype)

        for i in range(self.num_layers):
            attn1, _ = self.transformer_layers[i][0][0](
                src,
                torch.transpose(src, 1, 2),
                attn_mask=attn_mask
            )
            attn2, _ = self.transformer_layers[i][1][0](
                src,
                torch.transpose(src, 1, 2),
                attn_mask=attn_mask
            )
            src = src + self.dropout(attn1 + attn2)

        return self.layernorm2(src)

class Decoder(nn.Module):
    def __init__(self, embed_dim, num_layers, num_heads, num_pos, num_tokens):
        super(Decoder, self).__init__()
        self.embed_dim = embed_dim
        self.num_layers = num_layers
        self.num_heads = num_heads
        self.num_pos = num_pos
        self.num_tokens = num_tokens

        self.pos_embed = nn.Parameter(torch.zeros(1, num_pos + 1, embed_dim))
        self.token_embed = nn.Embedding(num_tokens, embed_dim)
        self.layernorm1 = nn.LayerNorm(embed_dim)
        self.layernorm2 = nn.LayerNorm(embed_dim)
        self.dropout = nn.Dropout(0.1)

        self.transformer_layers = nn.ModuleList([
            nn.ModuleList([
                nn.ModuleList([
                    MultiHeadAttention(embed_dim, num_heads)
                    for _ in range(num_layers)
                ]) for _ in range(2)
            ]) for _ in range(num_layers)
        ])

    def forward(self, tgt, memory, tgt_len, memory_len):
        tgt_len = tgt.size(1)
        memory_len = memory.size(1)
        tgt = tgt * 1e-4
        tgt = tgt + self.pos_embed
        tgt = self.token_embed(tgt)
        tgt = self.layernorm1(tgt)

        attn_mask = None
        if memory_len > 0:
            attn_mask = torch.zeros((tgt_len, memory_len), device=tgt.device)
            attn_mask = attn_mask.wonil()
            attn_mask = attn_mask.to(tgt.dtype)

        for i in range(self.num_layers):
            attn1, _ = self.transformer_layers[i][0][0](
                tgt,
                memory,
                attn_mask=attn_mask
            )
            attn2, _ = self.transformer_layers[i][1][0](
                tgt,
                memory,
                attn_mask=attn_mask
            )
            tgt = tgt + self.dropout(attn1 + attn2)

        return self.layernorm2(tgt)

4.具體代碼實例和詳細解釋說明

在本節(jié)中,我們將通過一個簡單的例子來演示如何使用Transformer實現(xiàn)文本分類任務(wù)。我們將使用PyTorch和Transformer的實現(xiàn)來構(gòu)建一個簡單的文本分類模型。

import torch
import torch.nn as nn
from transformers import AdamW

# 定義數(shù)據(jù)加載器
# 假設(shè)我們已經(jīng)定義了數(shù)據(jù)加載器train_loader和val_loader

# 定義模型
class TextClassifier(nn.Module):
    def __init__(self, num_tokens, embed_dim, num_heads, num_layers):
        super(TextClassifier, self).__init__()
        self.embed_dim = embed_dim
        self.num_heads = num_heads
        self.num_layers = num_layers

        self.token_embed = nn.Embedding(num_tokens, embed_dim)
        self.pos_embed = nn.Parameter(torch.zeros(1, num_tokens + 1, embed_dim))
        self.dropout = nn.Dropout(0.1)

        self.transformer_layers = nn.ModuleList([
            nn.ModuleList([
                MultiHeadAttention(embed_dim, num_heads)
                for _ in range(num_layers)
            ]) for _ in range(2)
        ])

        self.classifier = nn.Linear(embed_dim, num_tokens)

    def forward(self, src):
        src_len = src.size(1)
        src = src * 1e-4
        src = src + self.pos_embed
        src = self.token_embed(src)
        src = nn.functional.layer_norm(src, dim=1)

        attn_mask = None
        if src_len > 0:
            attn_mask = torch.zeros((src_len, src_len), device=src.device)
            attn_mask = attn_mask.wonil()
            attn_mask = attn_mask.to(src.dtype)

        for i in range(self.num_layers):
            attn1, _ = self.transformer_layers[i][0][0](
                src,
                torch.transpose(src, 1, 2),
                attn_mask=attn_mask
            )
            attn2, _ = self.transformer_layers[i][1][0](
                src,
                torch.transpose(src, 1, 2),
                attn_mask=attn_mask
            )
            src = src + self.dropout(attn1 + attn2)

        return self.classifier(src)

# 訓(xùn)練模型
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = TextClassifier(num_tokens, embed_dim, num_heads, num_layers).to(device)
optimizer = AdamW(model.parameters(), lr=1e-5)

for epoch in range(num_epochs):
    for batch in train_loader:
        src = batch.src.to(device)
        tgt = batch.tgt.to(device)

        model.zero_grad()
        output = model(src)
        loss = nn.functional.cross_entropy(output, tgt)
        loss.backward()
        optimizer.step()

5.未來發(fā)展趨勢和挑戰(zhàn)

5.1 未來發(fā)展趨勢

隨著Transformer在NLP領(lǐng)域的成功應(yīng)用,我們可以預(yù)見以下幾個方面的未來發(fā)展趨勢:

  • 更大的預(yù)訓(xùn)練模型:隨著計算資源的不斷提升,我們可以預(yù)見更大的預(yù)訓(xùn)練模型,這些模型將具有更多的參數(shù),從而在各種NLP任務(wù)中表現(xiàn)更強。

  • 跨領(lǐng)域的應(yīng)用:Transformer不僅可以應(yīng)用于NLP任務(wù),還可以應(yīng)用于其他領(lǐng)域,例如計算機視覺、醫(yī)學(xué)圖像分析等。

  • 更高效的訓(xùn)練方法:隨著數(shù)據(jù)規(guī)模的增加,訓(xùn)練大型模型的時間和成本將成為挑戰(zhàn)。因此,我們可以預(yù)見更高效的訓(xùn)練方法的出現(xiàn),例如分布式訓(xùn)練、異構(gòu)計算等。

5.2 挑戰(zhàn)

盡管Transformer在NLP領(lǐng)域取得了顯著的成功,但仍然存在一些挑戰(zhàn):

  • 解釋性和可解釋性:Transformer模型通常被認為是“黑盒”模型,因為它們的內(nèi)部工作原理難以解釋。這限制了我們對模型的理解,并使得在一些敏感應(yīng)用中使用Transformer模型變得困難。

  • 計算資源:雖然Transformer模型在性能方面取得了顯著進展,但它們?nèi)匀恍枰罅康挠嬎阗Y源。這限制了它們在資源有限的環(huán)境中的應(yīng)用。

  • 數(shù)據(jù)偏見:Transformer模型依賴于大量的預(yù)訓(xùn)練數(shù)據(jù),因此它們可能會傳播在訓(xùn)練數(shù)據(jù)中存在的偏見。這限制了它們在處理新任務(wù)或處理不同于訓(xùn)練數(shù)據(jù)的輸入的能力。

6.附錄

附錄A:常見問題解答

問題1:如何選擇embed_dim、num_heads和num_layers?

答:在實際應(yīng)用中,我們可以通過實驗不同的組合來選擇最佳的embed_dim、num_heads和num_layers。通常情況下,embed_dim在512和1024之間,num_heads在2和8之間,num_layers在2和6之間。

問題2:如何處理長序列?

答:Transformer模型不適合處理長序列,因為它們使用了自注意力機制,這會導(dǎo)致時間復(fù)雜度為O(n^2)。為了處理長序列,我們可以使用位置編碼或?qū)㈤L序列拆分為多個短序列。

問題3:如何使用預(yù)訓(xùn)練的Transformer模型?

答:我們可以使用 Hugging Face的Transformers庫來使用預(yù)訓(xùn)練的Transformer模型。這個庫提供了許多預(yù)訓(xùn)練的模型,如BERT、GPT-2、RoBERTa等。我們只需要下載對應(yīng)的預(yù)訓(xùn)練模型和權(quán)重,然后使用它們進行下游任務(wù)。

問題4:如何訓(xùn)練自定義的Transformer模型?

答:我們可以使用PyTorch和Transformers庫來訓(xùn)練自定義的Transformer模型。首先,我們需要定義模型結(jié)構(gòu),然后使用適當(dāng)?shù)膬?yōu)化器和損失函數(shù)進行訓(xùn)練。在訓(xùn)練過程中,我們可以使用批量梯度下降(BGD)或者隨機梯度下降(SGD)等優(yōu)化算法。

問題5:如何使用Transformer模型進行文本生成?

答:我們可以使用生成預(yù)訓(xùn)練的Transformer模型,如GPT-2或GPT-3。在使用過程中,我們可以設(shè)置一個隨機的開頭序列,然后使用模型生成完整的序列。通常情況下,我們需要對生成的序列進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的生成結(jié)果。

問題6:如何使用Transformer模型進行文本摘要?

答:我們可以使用抽取預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將文本摘要任務(wù)視為一個序列摘要任務(wù),然后使用模型對輸入序列進行摘要。通常情況下,我們需要對生成的摘要進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的摘要結(jié)果。

問題7:如何使用Transformer模型進行文本摘要?

答:我們可以使用抽取預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將文本摘要任務(wù)視為一個序列摘要任務(wù),然后使用模型對輸入序列進行摘要。通常情況下,我們需要對生成的摘要進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的摘要結(jié)果。

問題8:如何使用Transformer模型進行文本分類?

答:我們可以使用分類預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將文本分類任務(wù)視為一個序列分類任務(wù),然后使用模型對輸入序列進行分類。通常情況下,我們需要對生成的分類結(jié)果進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的分類結(jié)果。

問題9:如何使用Transformer模型進行命名實體識別(NER)?

答:我們可以使用NER預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將命名實體識別任務(wù)視為一個序列標(biāo)注任務(wù),然后使用模型對輸入序列進行標(biāo)注。通常情況下,我們需要對生成的標(biāo)注結(jié)果進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的標(biāo)注結(jié)果。

問題10:如何使用Transformer模型進行情感分析?

答:我們可以使用情感分析預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將情感分析任務(wù)視為一個序列分類任務(wù),然后使用模型對輸入序列進行分類。通常情況下,我們需要對生成的分類結(jié)果進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的分類結(jié)果。

問題11:如何使用Transformer模型進行文本 summarization?

答:我們可以使用摘要預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將文本摘要任務(wù)視為一個序列摘要任務(wù),然后使用模型對輸入序列進行摘要。通常情況下,我們需要對生成的摘要進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的摘要結(jié)果。

問題12:如何使用Transformer模型進行文本生成?

答:我們可以使用生成預(yù)訓(xùn)練的Transformer模型,如GPT-2或GPT-3。在使用過程中,我們可以設(shè)置一個隨機的開頭序列,然后使用模型生成完整的序列。通常情況下,我們需要對生成的序列進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的生成結(jié)果。

問題13:如何使用Transformer模型進行機器翻譯?

答:我們可以使用機器翻譯預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將機器翻譯任務(wù)視為一個序列翻譯任務(wù),然后使用模型對輸入序列進行翻譯。通常情況下,我們需要對生成的翻譯結(jié)果進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的翻譯結(jié)果。

問題14:如何使用Transformer模型進行問答系統(tǒng)?

答:我們可以使用問答預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將問答任務(wù)視為一個序列生成任務(wù),然后使用模型對輸入問題生成答案。通常情況下,我們需要對生成的答案進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的答案結(jié)果。

問題15:如何使用Transformer模型進行文本生成?

答:我們可以使用生成預(yù)訓(xùn)練的Transformer模型,如GPT-2或GPT-3。在使用過程中,我們可以設(shè)置一個隨機的開頭序列,然后使用模型生成完整的序列。通常情況下,我們需要對生成的序列進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的生成結(jié)果。

問題16:如何使用Transformer模型進行文本摘要?

答:我們可以使用抽取預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將文本摘要任務(wù)視為一個序列摘要任務(wù),然后使用模型對輸入序列進行摘要。通常情況下,我們需要對生成的摘要進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的摘要結(jié)果。

問題17:如何使用Transformer模型進行文本分類?

答:我們可以使用分類預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將文本分類任務(wù)視為一個序列分類任務(wù),然后使用模型對輸入序列進行分類。通常情況下,我們需要對生成的分類結(jié)果進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的分類結(jié)果。

問題18:如何使用Transformer模型進行命名實體識別(NER)?

答:我們可以使用NER預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將命名實體識別任務(wù)視為一個序列標(biāo)注任務(wù),然后使用模型對輸入序列進行標(biāo)注。通常情況下,我們需要對生成的標(biāo)注結(jié)果進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的標(biāo)注結(jié)果。

問題19:如何使用Transformer模型進行情感分析?

答:我們可以使用情感分析預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將情感分析任務(wù)視為一個序列分類任務(wù),然后使用模型對輸入序列進行分類。通常情況下,我們需要對生成的分類結(jié)果進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的分類結(jié)果。

問題20:如何使用Transformer模型進行文本 summarization?

答:我們可以使用摘要預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將文本摘要任務(wù)視為一個序列摘要任務(wù),然后使用模型對輸入序列進行摘要。通常情況下,我們需要對生成的摘要進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的摘要結(jié)果。

問題21:如何使用Transformer模型進行文本生成?

答:我們可以使用生成預(yù)訓(xùn)練的Transformer模型,如GPT-2或GPT-3。在使用過程中,我們可以設(shè)置一個隨機的開頭序列,然后使用模型生成完整的序列。通常情況下,我們需要對生成的序列進行裁剪和去除重復(fù)的內(nèi)容,以獲得更好的生成結(jié)果。

問題22:如何使用Transformer模型進行機器翻譯?

答:我們可以使用機器翻譯預(yù)訓(xùn)練的Transformer模型,如BERT或RoBERTa。在使用過程中,我們可以將機器翻譯任務(wù)視為一個序列翻譯任務(wù),然后使用模型對輸入序列進行翻譯。通常情況下,我們需要對

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容