機器學習深度學習——seq2seq實現機器翻譯(詳細實現與原理推導)

👨?🎓作者簡介:一位即將上大四,正專攻機器學習的保研er
🌌上期文章:機器學習&&深度學習——seq2seq實現機器翻譯(數據集處理)
📚訂閱專欄:機器學習&&深度學習
希望文章對你們有所幫助

之前已經講解過了seq2seq,且已經將機器翻譯的數據集導入和預處理好了,接下來就要利用該數據集進行訓練。

seq2seq實現機器翻譯(詳細實現與原理推導)

  • 引入
  • 編碼器
  • 解碼器
  • 損失函數
  • 訓練
  • 預測
  • 預測序列的評估
  • 小結

引入

在這里插入圖片描述
我們的任務就是構建上面的設計,并將之前的數據集用來訓練這個模型。

import collections
import math
import torch
from torch import nn
from d2l import torch as d2l

編碼器

技術上說,編碼器就是將長度可變的輸入序列轉換成形狀固定的上下文變量c,并將輸入序列的信息在該上下文變量中進行編碼。
考慮由一個序列組成的樣本(批量大小為1)。假設輸入序列是:
x 1 , . . . , x T 其中 x t 是輸入文本序列中的第 t 個詞元 x_1,...,x_T\\ 其中x_t是輸入文本序列中的第t個詞元 x1?,...,xT?其中xt?是輸入文本序列中的第t個詞元
在時間步t,循環神經網絡將詞元xt的輸入特征向量和上一時間步的隱狀態轉換為當前步的隱狀態,使用函數f來描述循環神經網絡的循環層所做的變換:
h t = f ( x t , h t ? 1 ) h_t=f(x_t,h_{t-1}) ht?=f(xt?,ht?1?)
總之,編碼器通過選定的函數q, 將所有時間步的隱狀態轉換為上下文變量:
c = q ( h 1 , . . . , h T ) c=q(h_1,...,h_T) c=q(h1?,...,hT?)
比如,當
q ( h 1 , . . . , h T ) = h T q(h_1,...,h_T)=h_T q(h1?,...,hT?)=hT?
時,上下文變量僅僅是輸入序列在最后時間步的隱狀態。
到目前,我們使用的是一個單向循環神經網絡來設計編碼器,隱狀態只依賴于輸入子序列,這個子序列是由輸入序列的開始位置到隱狀態所在的時間步的位置(包括隱狀態所在的時間步)組成。我們也可以使用雙向循環神經網絡構造編碼器,隱狀態對整個序列的信息都進行了編碼。
現在開始實現循環神經網絡編碼器,我們使用了嵌入層來獲得輸入序列的每個詞元的特征向量。嵌入層的權重是一個矩陣,其行數等于輸入詞表的大小(vocab_size),其列數等于特征向量的維度(embed_size)。這里選擇了一個多層門控循環單元來實現編碼器:

#@save
class Seq2SeqEncoder(d2l.Encoder):"""用于序列到序列學習的循環神經網絡編碼器"""def __init__(self, vocab_size, embed_size, num_hiddens, num_layers,dropout=0, **kwargs):super(Seq2SeqEncoder, self).__init__(**kwargs)# 嵌入層self.embedding = nn.Embedding(vocab_size, embed_size)self.rnn = nn.GRU(embed_size, num_hiddens, num_layers,dropout=dropout)def forward(self, X, *args):# 輸出'X'的形狀:(batch_size,num_steps,embed_size)X = self.embedding(X)# 在循環神經網絡模型中,第一個軸對應于時間步X = X.permute(1, 0, 2)# 如果未提及狀態,則默認為0output, state = self.rnn(X)# output的形狀:(num_steps,batch_size,num_hiddens)# state的形狀:(num_layers,batch_size,num_hiddens)return output, state

接著我們實例化上述編碼器的實現,使用一個兩層門控循環單元編碼器,其隱藏單元數為16。給定一小批量的輸入序列X(批量大小為4,時間步為7)。在完成所有時間步后,最后一層的隱狀態的輸出是一個張量(output由編碼器的循環層返回),形狀為(時間步數,批量大小,隱藏單元數)。

encoder = Seq2SeqEncoder(vocab_size=10, embed_size=8, num_hiddens=16,num_layers=2)
encoder.eval()
X = torch.zeros((4, 7), dtype=torch.long)
output, state = encoder(X)
print(output.shape)

運行結果:

torch.Size([7, 4, 16])

解碼器

編碼器輸出的上下文變量c對整個輸入序列進行編碼。而來自訓練數據集的輸出序列
y 1 , y 2 , . . . , y T ′ y_1,y_2,...,y_{T^{'}} y1?,y2?,...,yT?
對于每個時間步t(與輸入序列或編碼器的時間步t不同),解碼器輸出的概率取決于先前的輸出子序列
y 1 , . . . , y t ′ ? 1 y_1,...,y_{t^{'}-1} y1?,...,yt?1?
和上下文變量c,即
P ( y t ′ ∣ y 1 , . . . , y t ′ ? 1 , c ) P(y_{t^{'}}|y_1,...,y_{t^{'}-1},c) P(yt?y1?,...,yt?1?,c)
為了在序列上模型化這種概率,我們可以使用另一個循環神經網絡作為解碼器。在輸出序列上的任意時間步t,循環神經網絡將來自上一時間步的輸出和上下文c作為輸入,然后再當前時間步將它們和上一隱狀態轉換為當前時間步的隱狀態。可用g表示解碼器的隱藏層的變換:
s t ′ = g ( y t ′ ? 1 , c , s t ′ ? 1 ) s_{t^{'}}=g(y_{t^{'}-1},c,s_{t^{'}-1}) st?=g(yt?1?,c,st?1?)
獲得解碼器隱狀態后,我們可以使用輸出層和softmax操作來計算在時間步t時輸出y_{t^{'}}的條件概率分布:
P ( y t ′ ∣ y 1 , . . . , y t ′ ? 1 , c ) P(y_{t^{'}}|y_1,...,y_{t^{'}-1},c) P(yt?y1?,...,yt?1?,c)
當實現解碼器時,我們直接使用編碼器的最后一個時間步的隱狀態來初始化解碼器的隱狀態。這就要求使用編碼器和解碼器要有相同數量的層和隱藏單元。
為了進一步包含經過編碼的輸入序列的信息,上下文變量在所有的時間步與解碼器的輸入進行拼接。為了預測輸出詞元的概率分布,在循環神經網絡解碼器的最后一層使用全連接層來變換隱狀態。

class Seq2SeqDecoder(d2l.Decoder):"""用于序列到序列學習的循環神經網絡解碼器"""def __init__(self, vocab_size, embed_size, num_hiddens, num_layers,dropout=0, **kwargs):super(Seq2SeqDecoder, self).__init__(**kwargs)self.embedding = nn.Embedding(vocab_size, embed_size)self.rnn = nn.GRU(embed_size + num_hiddens, num_hiddens, num_layers,dropout=dropout)self.dense = nn.Linear(num_hiddens, vocab_size)def init_state(self, enc_outputs, *args):return enc_outputs[1]def forward(self, X, state):# 輸出'X'的形狀:(batch_size,num_steps,embed_size)X = self.embedding(X).permute(1, 0, 2)# 廣播context,使其具有與X相同的num_stepscontext = state[-1].repeat(X.shape[0], 1, 1)X_and_context = torch.cat((X, context), 2)output, state = self.rnn(X_and_context, state)output = self.dense(output).permute(1, 0, 2)# output的形狀:(batch_size,num_steps,vocab_size)# state的形狀:(num_layers,batch_size,num_hiddens)return output, state

下面我們輸出一下解碼器的輸出形狀:

decoder = Seq2SeqDecoder(vocab_size=10, embed_size=8, num_hiddens=16,num_layers=2)
decoder.eval()
state = decoder.init_state(encoder(X))
output, state = decoder(X, state)
print(output.shape, state.shape)

輸出結果:

torch.Size([4, 7, 10]) torch.Size([2, 4, 16])

顯然,解碼器的輸出形狀變為(批量大小,時間步數,詞表大小),其中張量的最后一個維度存儲預測的詞元分布。
上述循環神經網絡“編碼器-解碼器”模型中的各層如下所示:
在這里插入圖片描述

損失函數

在每個時間步,解碼器預測了輸出詞元的概率分布,可以使用softmax來獲得分布, 并通過計算交叉熵損失函數來進行優化,數據集中的詞元可能是被填充過的,因此,我們應該將填充詞元的預測排除在損失函數的計算之外。
我們使用sequence_mask函數,通過零值化屏蔽不相關的項, 以便后面任何不相關預測的計算都是與零的乘積,結果都等于零。

#@save
def sequence_mask(X, valid_len, value=0):"""在序列中屏蔽不相關的項"""maxlen = X.size(1)mask = torch.arange((maxlen), dtype=torch.float32,device=X.device)[None, :] < valid_len[:, None]X[~mask] = valuereturn X

現在,我們可以通過擴展softmax交叉熵損失函數來遮蔽不相關的預測。最初,所有預測詞元的掩碼都設置為1。一旦給定了有效長度,與填充詞元對應的掩碼將被設置為0。最后,將所有詞元的損失乘以掩碼,以過濾掉損失中填充詞元產生的不相關預測。

#@save
class MaskedSoftmaxCELoss(nn.CrossEntropyLoss):"""帶遮蔽的softmax交叉熵損失函數"""# pred的形狀:(batch_size,num_steps,vocab_size)# label的形狀:(batch_size,num_steps)# valid_len的形狀:(batch_size,)def forward(self, pred, label, valid_len):weights = torch.ones_like(label)weights = sequence_mask(weights, valid_len)self.reduction='none'unweighted_loss = super(MaskedSoftmaxCELoss, self).forward(pred.permute(0, 2, 1), label)weighted_loss = (unweighted_loss * weights).mean(dim=1)return weighted_loss

訓練

#@save
def train_seq2seq(net, data_iter, lr, num_epochs, tgt_vocab, device):"""訓練序列到序列模型"""def xavier_init_weights(m):if type(m) == nn.Linear:nn.init.xavier_uniform_(m.weight)if type(m) == nn.GRU:for param in m._flat_weights_names:if "weight" in param:nn.init.xavier_uniform_(m._parameters[param])net.apply(xavier_init_weights)net.to(device)optimizer = torch.optim.Adam(net.parameters(), lr=lr)loss = MaskedSoftmaxCELoss()net.train()animator = d2l.Animator(xlabel='epoch', ylabel='loss',xlim=[10, num_epochs])for epoch in range(num_epochs):timer = d2l.Timer()metric = d2l.Accumulator(2)  # 訓練損失總和,詞元數量for batch in data_iter:optimizer.zero_grad()X, X_valid_len, Y, Y_valid_len = [x.to(device) for x in batch]bos = torch.tensor([tgt_vocab['<bos>']] * Y.shape[0],device=device).reshape(-1, 1)dec_input = torch.cat([bos, Y[:, :-1]], 1)  # 強制教學Y_hat, _ = net(X, dec_input, X_valid_len)l = loss(Y_hat, Y, Y_valid_len)l.sum().backward()      # 損失函數的標量進行“反向傳播”d2l.grad_clipping(net, 1)num_tokens = Y_valid_len.sum()optimizer.step()with torch.no_grad():metric.add(l.sum(), num_tokens)if (epoch + 1) % 10 == 0:animator.add(epoch + 1, (metric[0] / metric[1],))print(f'loss {metric[0] / metric[1]:.3f}, {metric[1] / timer.stop():.1f} 'f'tokens/sec on {str(device)}')

現在就可以創建和訓練一個循環神經網絡“編碼器-解碼器”模型用于序列到序列的學習。

embed_size, num_hiddens, num_layers, dropout = 32, 32, 2, 0.1
batch_size, num_steps = 64, 10
lr, num_epochs, device = 0.005, 300, d2l.try_gpu()train_iter, src_vocab, tgt_vocab = d2l.load_data_nmt(batch_size, num_steps)
encoder = Seq2SeqEncoder(len(src_vocab), embed_size, num_hiddens, num_layers,dropout)
decoder = Seq2SeqDecoder(len(tgt_vocab), embed_size, num_hiddens, num_layers,dropout)
net = d2l.EncoderDecoder(encoder, decoder)
train_seq2seq(net, train_iter, lr, num_epochs, tgt_vocab, device)
d2l.plt.show()

輸出結果:

loss 0.020, 9040.7 tokens/sec on cpu

運行圖片:
在這里插入圖片描述

預測

與訓練類似,序列開始詞元bos在初始時間步被輸入到解碼器中。 當輸出序列的預測遇到序列結束詞元eos時,預測就結束了。
在這里插入圖片描述

#@save
def predict_seq2seq(net, src_sentence, src_vocab, tgt_vocab, num_steps,device, save_attention_weights=False):"""序列到序列模型的預測"""# 在預測時將net設置為評估模式net.eval()src_tokens = src_vocab[src_sentence.lower().split(' ')] + [src_vocab['<eos>']]enc_valid_len = torch.tensor([len(src_tokens)], device=device)src_tokens = d2l.truncate_pad(src_tokens, num_steps, src_vocab['<pad>'])# 添加批量軸enc_X = torch.unsqueeze(torch.tensor(src_tokens, dtype=torch.long, device=device), dim=0)enc_outputs = net.encoder(enc_X, enc_valid_len)dec_state = net.decoder.init_state(enc_outputs, enc_valid_len)# 添加批量軸dec_X = torch.unsqueeze(torch.tensor([tgt_vocab['<bos>']], dtype=torch.long, device=device), dim=0)output_seq, attention_weight_seq = [], []for _ in range(num_steps):Y, dec_state = net.decoder(dec_X, dec_state)# 我們使用具有預測最高可能性的詞元,作為解碼器在下一時間步的輸入dec_X = Y.argmax(dim=2)pred = dec_X.squeeze(dim=0).type(torch.int32).item()# 保存注意力權重(稍后討論)if save_attention_weights:attention_weight_seq.append(net.decoder.attention_weights)# 一旦序列結束詞元被預測,輸出序列的生成就完成了if pred == tgt_vocab['<eos>']:breakoutput_seq.append(pred)return ' '.join(tgt_vocab.to_tokens(output_seq)), attention_weight_seq

預測序列的評估

原則上,對預測序列中的任意n元語法,BLEU的評估都是這個n元語法是否出現在序列標簽中。
我們將BLEU定義為:
e x p ( m i n ( 0 , 1 ? l e n l a b e l l e n p r e d ) ) ∏ n = 1 k p n 1 / 2 n 其中, l e n l a b e l 是標簽序列的詞元數, l e n p r e d 表示序列預測中的詞元數 , k 是用于匹配的最長 n 元語法 p n 表示 n 元語法的精確度, p n = 預測序列與標簽序列中匹配的 n 元語法的數量 預測序列中 n 元語法的數量 exp(min(0,1-\frac{len_{label}}{len_{pred}}))\prod_{n=1}^kp_n^{1/2^n}\\ 其中,len_{label}是標簽序列的詞元數,len_{pred}表示序列預測中的詞元數,k是用于匹配的最長n元語法\\ p_n表示n元語法的精確度,p_n=\frac{預測序列與標簽序列中匹配的n元語法的數量}{預測序列中n元語法的數量} exp(min(0,1?lenpred?lenlabel??))n=1k?pn1/2n?其中,lenlabel?是標簽序列的詞元數,lenpred?表示序列預測中的詞元數,k是用于匹配的最長n元語法pn?表示n元語法的精確度,pn?=預測序列中n元語法的數量預測序列與標簽序列中匹配的n元語法的數量?
比如,我們給定標簽序列為ABCDEF,預測序列為ABBCD,顯然p1=4/5,p2=3/4,p3=1/3,p4=0。
我們可以再次剖析一下上式的細節,可以發現上式有多“妙”:
1、我們知道,n元語法越長,匹配難度越大,所以我們如果對于越長的且匹配了的n元語法,應該給與更大的支持,而BLEU正是這樣,為更長的n元語法的精確度分配了更大的權重:
當 p n 固定時, p n 1 / 2 n 會隨著 n 的增長而增加(注意 p n 顯然恒小于 1 ) 當p_n固定時,p_n^{1/2^n}會隨著n的增長而增加(注意p_n顯然恒小于1) pn?固定時,pn1/2n?會隨著n的增長而增加(注意pn?顯然恒小于1
2、由于預測的序列越短,獲得的pn值會越高,因此我們需要對其進行懲罰:
m i n ( 0 , 1 ? l e n l a b e l l e n p r e d ) min(0,1-\frac{len_{label}}{len_{pred}}) min(0,1?lenpred?lenlabel??)
可以看出,序列很短的時候,利用這個式子也會使得exp更小,從而降低BLEU。
BLEU的代碼實現如下:

def bleu(pred_seq, label_seq, k):  #@save"""計算BLEU"""pred_tokens, label_tokens = pred_seq.split(' '), label_seq.split(' ')len_pred, len_label = len(pred_tokens), len(label_tokens)score = math.exp(min(0, 1 - len_label / len_pred))for n in range(1, k + 1):num_matches, label_subs = 0, collections.defaultdict(int)for i in range(len_label - n + 1):label_subs[' '.join(label_tokens[i: i + n])] += 1for i in range(len_pred - n + 1):if label_subs[' '.join(pred_tokens[i: i + n])] > 0:num_matches += 1label_subs[' '.join(pred_tokens[i: i + n])] -= 1score *= math.pow(num_matches / (len_pred - n + 1), math.pow(0.5, n))return score

現在,利用訓練好的循環神經網絡“編碼器-解碼器”模型, 將幾個英語句子翻譯成法語,并和訓練數據中的法語比較,計算BLEU的最終結果:

engs = ['go .', "i lost .", 'he\'s calm .', 'i\'m home .']
fras = ['va !', 'j\'ai perdu .', 'il est calme .', 'je suis chez moi .']
for eng, fra in zip(engs, fras):translation, attention_weight_seq = predict_seq2seq(net, eng, src_vocab, tgt_vocab, num_steps, device)print(f'{eng} => {translation}, bleu {bleu(translation, fra, k=2):.3f}')

運行結果:

go . => va le foutre bras !, bleu 0.000
i lost . => j’ai perdu ., bleu 1.000
he’s calm . => il est paresseux ., bleu 0.658
i’m home . => je suis chez moi porte qui suis ., bleu 0.640

看起來這次的效果并不好,第一個翻譯出來的BLEU是0。
一個原因是我們的使用方法還是太原始了(seq2seq使用貪心的方式,下一個詞元直接選概率高的,學過動態規劃就知道這個不一定為最優)。
一個很好的序列生成策略是束搜索,將在之后講解。

小結

1、根據“編碼器-解碼器”架構的設計, 我們可以使用兩個循環神經網絡來設計一個序列到序列學習的模型。
2、在實現編碼器和解碼器時,我們可以使用多層循環神經網絡。
3、我們可以使用遮蔽來過濾不相關的計算,例如在計算損失時。
4、在“編碼器-解碼器”訓練中,強制教學方法將原始輸出序列(而非預測結果)輸入解碼器。
5、BLEU是一種常用的評估方法,它通過測量預測序列和標簽序列之間的元語法的匹配度來評估預測。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/35424.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/35424.shtml
英文地址,請注明出處:http://en.pswp.cn/news/35424.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

機器學習編譯系列

機器學習編譯MLC 1. 引言2. 機器學習編譯--概述2.1 什么是機器學習編譯 1. 引言 陳天奇目前任教于CMU&#xff0c;研究方向為機器學習系統。他是TVM、MXNET、XGBoost的主要作者。2022年夏天&#xff0c;陳天奇在B站開設了《機器學習編譯》的課程。 ??《機器學習編譯》課程共分…

立即開始使用 3D 圖像

一、說明 這個故事介紹了使用這種類型的數據來訓練機器學習3D模型。特別是&#xff0c;我們討論了Kaggle中可用的MNIST數據集的3D版本&#xff0c;以及如何使用Keras訓練模型識別3D數字。 3D 數據無處不在。由于我們希望構建AI來與我們的物理世界進行交互&#xff0c;因此使用3…

了解 Langchain?是個啥?:第 1 部分

一、說明 在日常生活中&#xff0c;我們主要致力于構建端到端的應用程序。我們可以使用許多自動 ML 平臺和 CI/CD 管道來自動化 ml 管道。我們還有像Roboflow和Andrew N.G.的登陸AI這樣的工具來自動化或創建端到端的計算機視覺應用程序。 如果我們想在OpenAI或擁抱臉的幫助下創…

Day 26 C++ list容器(鏈表)

文章目錄 list基本概念定義結構雙向迭代器優點缺點List和vector區別存儲結構內存管理迭代器穩定性隨機訪問效率 list構造函數——創建list容器函數原型示例 list 賦值和交換函數原型 list 大小操作函數原型示例 list 插入和刪除函數原型示例 list 數據存取函數原型注意示例 lis…

論文詳解 ——《SNR-Aware Low-light Image Enhancement》

文章目錄 Abstract1.Introduction2. Related Work3. Our Method3.1 Long- and Short-range Branches3.2 SNR-based Spatially-varying Feature Fusion3.3 SNR-guided Attention in Transformer3.4 Loss Function 4. Experiments4.1. Datasets and Implementation Details4.2 Co…

SpringBoot | 使用newWorkStealingPool和CompletableFuture進行并發異步處理

關注wx&#xff1a; CodingTechWork 需求 一個列表操作需要異步處理每個元素&#xff0c;最終需要將列表各個元素的操作結果統一返回&#xff0c;無需關注該列表中的順序執行。這個線程池不會保證任務的順序執行&#xff0c;即為WorkStealing搶占式的工作。 開發模板 線程池…

基于SpringBoot實現MySQL備份與還原

基于SpringBoot實現MySQL備份與還原&#xff0c;需求是在頁面上對所有的平臺數據執行備份和恢復操作&#xff0c;那么就需要使用代碼去調用MySQL備份和恢復的指令&#xff0c;下面是具體實現步驟&#xff1b; MySQL備份表設計 CREATE TABLE IF NOT EXISTS mysql_backups (id …

6.1 安全漏洞與網絡攻擊

數據參考&#xff1a;CISP官方 目錄 安全漏洞及產生原因信息收集與分析網絡攻擊實施后門設置與痕跡清除 一、安全漏洞及產生原因 什么是安全漏洞 安全漏洞也稱脆弱性&#xff0c;是計算機系統存在的缺陷 漏洞的形式 安全漏洞以不同形式存在漏洞數量逐年遞增 漏洞產生的…

前端開發:數組對象判斷重復的方法詳解

前言 在前端開發過程中,關于數據處理是非常常用的操作,尤其是通過算法處理從后端獲取的數據甚為重要。而且在前端開發中,兩大類型的數據處理是必備的:數組和對象。與其說是數據處理,不如說是數組和對象的處理。實際開發中,關于數組數據的處理所占比例更高,尤其是涉及到表…

使用Flask.Request的方法和屬性,獲取get和post請求參數(二)

1、Flask中的request 在Python發送Post、Get等請求時&#xff0c;我們使用到requests庫。Flask中有一個request庫&#xff0c;有其特有的一些方法和屬性&#xff0c;注意跟requests不是同一個。 2、Post請求&#xff1a;request.get_data() 用于服務端獲取客戶端請求數據。注…

理解ConcurrentSkipListMap(有點類似于并發的TreeMap)

是一個分層的結構。 從最上面開始查找&#xff0c;最后層層往下查。 插入和刪除有可能會引起節點Level的變更。 key是有序的&#xff0c;因此可以看做是并發的TreeMap

ubuntu18.04下配置muduoC++11環境

1.安裝muduo依賴的編譯工具及庫 Cmake sudo apt-get install cmakeBoost sudo apt-get install libboost-dev libboost-test-devcurl、c-ares DNS、google protobuf sudo apt-get install libcurl4-openssl-dev libc-ares-dev sudo apt-get install protobuf-compiler libp…

帶你了解SpringBoot支持的復雜參數--自定義對象參數-自動封裝

&#x1f600;前言 本篇博文是關于SpringBoot 在響應客戶端請求時支持的復雜參數和自定義對象參數&#xff0c;希望您能夠喜歡&#x1f60a; &#x1f3e0;個人主頁&#xff1a;晨犀主頁 &#x1f9d1;個人簡介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章…

go struct 的常見問題

go struct 的常見問題 1. 什么是struct&#xff1f;2. 如何聲明、定義和創建一個struct&#xff1f;3. struct和其他數據類型&#xff08;如數組、切片、map等&#xff09;有什么區別&#xff1f;4. 如何訪問struct字段&#xff1f;5. struct是否支持繼承&#xff0c;是否支持重…

JavaWeb_xml

文章目錄 1.xml是什么&#xff1f;2.xml的用途 1.xml是什么&#xff1f; xml 是可擴展的標記性語言 2.xml的用途 1、用來保存數據&#xff0c;而且這些數據具有自我描述性 2、它還可以做為項目或者模塊的配置文件 3、還可以做為網絡傳輸數據的格式&#xff08;現在 JSON 為主…

【Github】SourceTree技巧匯總

sourceTree登錄github賬戶 會跳轉到瀏覽器端 按照Git Flow 初始化倉庫分支 克隆遠程倉庫到本地 推送變更到遠程倉庫 合并分支 可以看到目前的本地分支&#xff08;main、iOS_JS&#xff09;和遠程分支&#xff08;origin/main、origin/HEAD、origin/iOS_JS&#xff09;目前所處…

5134. 簡單判斷

文章目錄 Question輸入樣例1&#xff1a; 3 7 0 輸出樣例1&#xff1a; IdeasCode Question 給定三個非負整數 x,y,z &#xff0c;請你按如下要求進行判斷并輸出相應結果&#xff1a; 如果 x>yz &#xff0c;則輸出 。 如果 y>xz &#xff0c;則輸出 -。 如果 xy 且 z0…

pip install總是報錯:ValueError: Trusted host URL must include a host part: ‘#‘

一、問題現象 報錯信息如下&#xff1a; Traceback (most recent call last):File "/user_name/anaconda3/bin/pip", line 11, in <module>sys.exit(main())^^^^^^File "/user_name/anaconda3/lib/python3.11/site-packages/pip/_internal/cli/main.py&…

14_基于Flink將pulsar數據寫入到HBase

3.7.基于Flink將數據寫入到HBase 3.7.1.編寫Flink完成數據寫入到Hbase操作, 完成數據備份, 便于后續進行即席查詢和離線分析 3.7.1.1.HBase基本介紹 hbase是基于Google發布bigTable論文產生一款軟件, 是一款noSQL型數據, 不支持SQL. 不支持join的操作, 沒有表關系, 不支持事…