源碼有一個寫法:
def forward(self, input: Tensor, hx: Optional[Tensor] = None) -> Tuple[Tensor, Tensor]: # noqa: F811
????????pass
forward
,它的第一個參數(shù) input
是一個 Tensor
類型的變量,第二個參數(shù) hx
是一個可選的 Tensor
類型變量,這里使用了 Python 3.7 引入的類型注解語法。
函數(shù)返回值類型是一個由兩個 Tensor
類型變量組成的元組(Tuple)【 -> 的意思是返回值】
除此之外,這段代碼還包含了一個 pass
語句,它的作用是占位符,表示這個函數(shù)目前并沒有實現(xiàn)任何功能。如果你需要在這個函數(shù)中添加具體的代碼實現(xiàn),可以將這個 pass
語句替換為你的代碼。
2、@classmethod
@classmethod
是 Python 中的一個裝飾器(Decorator),用于定義類方法。
類方法是與類相關(guān)聯(lián)的方法,而不是與實例相關(guān)聯(lián)的方法。可以直接“類.方法”直接調(diào)用類方法而不需要實例化
使用 @classmethod
裝飾器來定義一個類方法,可以在方法中使用 cls
參數(shù)來引用類本身,而不是實例本身【在類方法中,第一個參數(shù)通常被約定為 cls
,表示類本身。然而,你可以使用任何名稱。】。例如:
class MyClass:
var = 123
@classmethod
def class_method(cls):
print(cls.var)
# 使用“@classmethod”的時候,可以直接調(diào)用類方法,不需要實例化
MyClass.class_method()
# 不使用“@classmethod”的時候,需要實例化才能調(diào)用類方法
class1 = MyClass()
class1.class_method()
在上面的示例代碼中,我們使用 @classmethod
裝飾器定義了一個名為 class_method
的類方法。在該方法中,我們使用 cls
參數(shù)來引用類本身,并打印了類變量 var
的值。最后,我們在不創(chuàng)建實例的情況下調(diào)用了該方法,輸出了類變量的值。
3、eval()?
eval() 可以將字符串形式的 Python 表達式作為參數(shù)進行求值
?例如上面的代碼,就可以將一個字符串轉(zhuǎn)為參數(shù)傳遞給方法了,因為有時候你需要動態(tài)變化你的參數(shù),所以就有了上面的寫法
4、nn.parameter()
nn.Parameter()
是 PyTorch 中用于將 tensor 轉(zhuǎn)換為 nn.Parameter
類型的函數(shù)。nn.Parameter
實際上是一個特殊的張量類型,它會被自動注冊為模型的可學習參數(shù),即在訓練過程中需要更新的參數(shù)。與普通的 Tensor 不同,nn.Parameter
的屬性包括要求梯度(requires_grad)和所處設(shè)備(device)等。
在 PyTorch 中,使用 nn.Parameter
將 tensor 轉(zhuǎn)換為模型參數(shù)有兩個好處:
-
自動追蹤計算圖:將 tensor 包裝為
nn.Parameter
之后,PyTorch 會自動將其加入計算圖中,并記錄相應的梯度信息,這樣就可以通過自動微分實現(xiàn)反向傳播,即計算模型參數(shù)的梯度。 -
方便管理模型參數(shù):使用
nn.Parameter
可以使得模型參數(shù)更方便地集中管理,例如可以使用model.parameters()
方法自動獲取模型中的所有參數(shù),或者使用model.named_parameters()
方法獲取模型中每個參數(shù)的名稱和值等信息。
使用 nn.Parameter
的一般流程是:首先定義一個 tensor,然后將其轉(zhuǎn)換成 nn.Parameter
類型并賦予初始值,最后將其添加到模型中作為可訓練參數(shù)。下面是一段示例代碼:
import torch.nn as nn
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.weight = nn.Parameter(torch.randn(3, 5)) # 定義可訓練參數(shù)為 3x5 的張量
self.bias = nn.Parameter(torch.zeros(3)) # 定義可訓練參數(shù)為長度為 3 的張量
def forward(self, x):
return torch.matmul(x, self.weight.t()) + self.bias # 使用可訓練參數(shù)計算輸出
在這個例子中,我們定義了一個 MyModel 類,并將 weight 和 bias 轉(zhuǎn)換為 nn.Parameter
類型。在模型的 forward 函數(shù)中,我們使用 weight 和 bias 計算輸出,這樣就可以利用反向傳播算法,根據(jù)損失函數(shù)對 weight 和 bias 進行梯度更新。
5、在forward函數(shù)中,self.multihead_attn(query, key, value)輸入是三個張量,初始化中的輸入是兩個張量 nn.MultiheadAttention(embed_dim, num_heads),這樣不會有問題嗎?
import torch
import torch.nn as nn
# 定義一個Multihead Attention層
class MultiheadAttentionLayer(nn.Module):
def __init__(self, embed_dim, num_heads):
super(MultiheadAttentionLayer, self).__init__()
# 定義查詢、鍵、值的線性變換
self.query_proj = nn.Linear(embed_dim, embed_dim)
self.key_proj = nn.Linear(embed_dim, embed_dim)
self.value_proj = nn.Linear(embed_dim, embed_dim)
# 定義多頭注意力機制
self.multihead_attn = nn.MultiheadAttention(embed_dim, num_heads)
# 定義Layer Norm
self.norm = nn.LayerNorm(embed_dim)
def forward(self, input):
# 將輸入張量拆分成查詢、鍵、值
query = self.query_proj(input)
key = self.key_proj(input)
value = self.value_proj(input)
# 調(diào)整形狀,以滿足Multihead Attention的輸入要求
query = query.permute(1, 0, 2)
key = key.permute(1, 0, 2)
value = value.permute(1, 0, 2)
# 計算Multihead Attention
attn_output, attn_weights = self.multihead_attn(query, key, value)
# 將輸出進行維度轉(zhuǎn)換,以滿足Layer Norm的輸入要求
attn_output = attn_output.permute(1, 0, 2)
# 應用Layer Norm和殘差連接
output = self.norm(input + attn_output)
return output
我們看到在init中使用了下面的代碼:
nn.MultiheadAttention(embed_dim, num_heads)
Q: 但是在forward函數(shù)中,在計算Multihead Attention的時候則是輸入了QKV三個張量,那么這時輸入三個張量,初始化的時候是兩個張量,這樣張量不是不匹配嗎?
attn_output, attn_weights = self.multihead_attn(query, key, value)
A: 沒有問題,因為初始化的時候調(diào)用的是nn.MultiheadAttention()的初始化方法:
# nn.MultiheadAttention() 源碼
def __init__(self, embed_dim, num_heads, dropout=0., bias=True, add_bias_kv=False, add_zero_attn=False, kdim=None, vdim=None):
super(MultiheadAttention, self).__init__()
self.embed_dim = embed_dim
self.kdim = kdim if kdim is not None else embed_dim
self.vdim = vdim if vdim is not None else embed_dim
self._qkv_same_embed_dim = self.kdim == embed_dim and self.vdim == embed_dim
self.num_heads = num_heads
self.dropout = dropout
self.head_dim = embed_dim // num_heads
assert self.head_dim * num_heads == self.embed_dim, "embed_dim must be divisible by num_heads"
而在forward輸入三個變量的時候是調(diào)用的nn.MultiheadAttention()的forward方法:
# nn.MultiheadAttention() 源碼
def forward(self, query, key, value, key_padding_mask=None,
need_weights=True, attn_mask=None):
# type: (Tensor, Tensor, Tensor, Optional[Tensor], bool, Optional[Tensor]) -> Tuple[Tensor, Optional[Tensor]]
6、解包操作 *XXX
*DNA_bound表示解包元組或列表
DNA_bound =?[32, 126]
np.random.randint(*DNA_bound, size=(pop_size, DNA_size)).astype(np.int8)
等于
np.random.randint(DNA_bound[0], DNA_bound[1], size=(pop_size, DNA_size)).astype(np.int8)
*DNA_bound用于將DNA_bound列表的兩個元素解包并作為參數(shù)傳遞給numpy.random模塊中的randint()函數(shù)。
具體來說,DNA_bound[0]和DNA_bound[1]分別表示DNA序列中每個基因的取值下限(閉區(qū)間)和取值上限(開區(qū)間),size=(pop_size, DNA_size)表示生成二維數(shù)組(即種群)的大小,而astype(np.int8)則是為了將生成的隨機數(shù)轉(zhuǎn)換成8位整型,以便后續(xù)進行ASCII編碼操作。
7、np.random.choice(a, size=None, replace=True, p=None)
np.random.choice(a, size=None, replace=True, p=None)
該函數(shù)從a序列或整數(shù)中隨機選擇元素,返回一個大小為size的新數(shù)組。其中,參數(shù)含義如下:
- a:一個整數(shù)或可迭代對象,表示待選元素;
- size:一個整數(shù)或元組,表示輸出數(shù)組的形狀,如果不傳遞這個參數(shù),則輸出一個標量;
- replace:一個布爾值,表示是否可以重復選擇元素,默認為True(允許重復選擇);
- p:一個與a長度相同的一維數(shù)組,表示每個元素被選擇的概率,如果不傳遞,則使用均勻分布進行隨機選擇。
例如,使用np.random.choice([1, 2, 3, 4, 5], size=(2, 3), replace=True, p=[0.1, 0.2, 0.3, 0.2, 0.2])生成一個大小為2×3的數(shù)組,表示從[1,2,3,4,5]這五個數(shù)中選取元素,其中元素1的選取概率是0.1,元素2的選取概率是0.2,依此類推。如果replace=False,則所選元素將不能重復。
結(jié)果:
[[1 4 5]
?[5 4 4]]
8、np.random.rand()
np.random.rand(1, 1)
np.random.rand(1, 1)
是一個NumPy函數(shù),用于返回指定形狀的隨機浮點數(shù)數(shù)組,其值位于[0, 1)之間。
在這里,np.random.rand(1, 1)
返回的是一個形狀為(1, 1)
的二維數(shù)組,即一個只有一個元素的矩陣(矩陣元素的值是一個范圍在[0, 1)之間的隨機浮點數(shù)),可以通過以下代碼查看:
import numpy as np
x = np.random.rand(1, 1)
print(x) # Output: [[0.12345678]]
9、np.empty()和np.zeros()
np.empty()
和np.zeros()
都是NumPy中用于創(chuàng)建數(shù)組的函數(shù),不同之處在于它們生成數(shù)組的方式不同:
-
np.empty(shape, dtype=float, order='C')
: 創(chuàng)建一個指定形狀和數(shù)據(jù)類型的空數(shù)組,其值未被初始化,得到的數(shù)組元素的值是隨機且未知的。由于NumPy對empty()
函數(shù)所返回的數(shù)組不進行初始化,因此使用該函數(shù)會快一些(但可能會有潛在的安全問題)。 -
np.zeros(shape, dtype=float, order='C')
: 創(chuàng)建一個指定形狀和數(shù)據(jù)類型的全0數(shù)組。
舉個例子,如果要創(chuàng)建一個全0數(shù)組,可以使用np.zeros()
函數(shù),如下所示:
import numpy as np
a = np.zeros((2, 3))
print(a) # Output: [[0. 0. 0.] # [0. 0. 0.]]
如果要創(chuàng)建一個空數(shù)組,可以使用np.empty()
,如下所示:
import numpy as np
b = np.empty((2, 3))
print(b) # Output: [[ 9.65677788e-316 2.07596591e-322 0.00000000e+000] # [ 0.00000000e+000 -1.49457197e+154 5.21297860e-321]]
需要注意的是,由于empty()
函數(shù)生成的數(shù)組未被初始化,其值可能是未知的,但其大小已經(jīng)確定。因此,在使用empty()
函數(shù)創(chuàng)建數(shù)組時,應該通過其他方式(例如使用zeros()
或ones()
)來初始化數(shù)組中的值。
10、np.empty()和np.empty_like()
kids = {'DNA': np.empty((n_kid, DNA_SIZE))}
kids['mut_strength'] = np.empty_like(kids['DNA'])
這段代碼創(chuàng)建了一個字典kids
,其中包括了兩個關(guān)鍵字'DNA'
和'mut_strength'
,分別對應空的二維數(shù)組np.empty((n_kid, DNA_SIZE))
和一個與'DNA'
數(shù)組大小相同的空數(shù)組 np.empty_like(kids['DNA'])
。
具體來說,np.empty((n_kid, DNA_SIZE))
函數(shù)的作用是創(chuàng)建一個形狀為(n_kid, DNA_SIZE)
的空NumPy數(shù)組,即創(chuàng)建一個包含n_kid
個長度為DNA_SIZE
的一維數(shù)組的二維數(shù)組。這里之所以使用np.empty()
而非np.zeros()
函數(shù),是因為empty()
函數(shù)生成的數(shù)組未被初始化,其值可能是未知的,但其大小已經(jīng)確定。
而np.empty_like(kids['DNA'])
也是創(chuàng)建一個形狀相同的空數(shù)組,不過是由kids['DNA']
這個數(shù)組的形狀來確定的。這里的作用是創(chuàng)建一個與'DNA'
同樣大小的空數(shù)組,用于存儲后面計算得到的變異強度。
總的來說,這段代碼的目的是創(chuàng)建一個字典kids
用于存儲下一代的DNA序列和其對應的變異強度,以備后續(xù)使用。
11、pop[np.argmax(fitness), :]
其中fitness是一個100行1列的矩陣
print("Most fitted DNA: ", pop[np.argmax(fitness), :])
這段代碼打印出了種群 `pop` 中適應度函數(shù)值最大的個體對應的DNA(基因表達式)。
其中,`np.argmax()` 函數(shù)返回數(shù)組中最大值的索引,‘:’表示取當前索引行的所有列,也就是取這一行的所有值,因此 `pop[np.argmax(fitness), :]` 表示在 `pop` 數(shù)組中找到適應度函數(shù)值最大的個體所對應的行,并將該行的所有元素作為輸出。
model.train()、model.backward(loss) 、model.step() 、val_outputs = model.module.validation_step(batch)這四個語句分別表示什么意思?
這四個語句所代表的含義如下:
-
model.train()
:這個語句用于將模型設(shè)置為訓練模式。在訓練模式下,模型會啟用一些特定的操作,如啟用Dropout、Batch Normalization等。這些操作在訓練過程中對于模型的性能和收斂非常重要。調(diào)用model.train()
可以切換模型到訓練模式,并保持這個狀態(tài),直到遇到model.eval()
語句或訓練結(jié)束為止。 -
model.backward(loss)
:這個語句用于計算損失函數(shù)(loss)對于模型參數(shù)的梯度。在反向傳播過程中,梯度會從損失函數(shù)向后傳播到模型的各個層,并根據(jù)鏈式法則逐層更新模型參數(shù)。 -
model.step()
:這個語句用于更新模型的參數(shù)。它會根據(jù)之前調(diào)用model.backward()
計算得到的梯度信息,使用優(yōu)化算法(如隨機梯度下降)來更新模型參數(shù)。通過迭代訓練數(shù)據(jù)并多次調(diào)用model.backward()
和model.step()
,模型的參數(shù)會逐漸優(yōu)化以最小化損失函數(shù)。 -
val_outputs = model.module.validation_step(batch)
:這個語句用于執(zhí)行模型的驗證步驟。通常,在訓練過程中,我們需要周期性地進行驗證以評估模型在驗證集上的性能。該語句會將驗證數(shù)據(jù)批次(batch)輸入到模型中,并返回模型在驗證數(shù)據(jù)上的輸出結(jié)果(val_outputs)。
next(data_iterator) + mpu.broadcast_data(keys, data, datatype)
data = next(data_iterator)
data_b = mpu.broadcast_data(keys, data, datatype)
這兩句代碼的含義如下:
-
data = next(data_iterator)
:這個語句用于從一個數(shù)據(jù)迭代器(data_iterator)中獲取下一個數(shù)據(jù)批次(batch)。通常在訓練模型時,數(shù)據(jù)會被劃分成小批次進行訓練,以便更高效地處理大規(guī)模數(shù)據(jù)集。這行代碼通過調(diào)用next()
函數(shù)從數(shù)據(jù)迭代器中獲取下一個批次的數(shù)據(jù),并將其賦值給變量data
供后續(xù)使用。 -
data_b = mpu.broadcast_data(keys, data, datatype)
:這個語句用于將數(shù)據(jù)擴散(broadcast)到不同設(shè)備或進程上。在分布式訓練中,多個設(shè)備或進程需要共享同一份數(shù)據(jù)。這行代碼通過調(diào)用mpu.broadcast_data()
函數(shù),將數(shù)據(jù)data
廣播到多個設(shè)備或進程上,并將廣播后的數(shù)據(jù)賦值給變量data_b
。
**將多個字典合并為一個字典
retrievals_all = {**retrieval_set_train, **retrieval_set_valid, **retrieval_set_test}
這行代碼使用了字典合并操作,將retrieval_set_train
、retrieval_set_valid
和retrieval_set_test
三個字典合并成一個新的字典retrievals_all
。
具體來說,代碼通過{**retrieval_set_train, **retrieval_set_valid, **retrieval_set_test}
的語法,使用兩個星號(**
)將三個字典展開,并將它們的鍵值對合并到一個新的字典中。
舉個例子來說明,假設(shè)原始的三個字典如下:
retrieval_set_train = {'apple': 1, 'banana': 2}
retrieval_set_valid = {'orange': 3, 'grape': 4}
retrieval_set_test = {'kiwi': 5, 'pear': 6}
通過執(zhí)行這行代碼后,將得到一個合并后的新字典retrievals_all
:文章來源:http://www.zghlxwxcb.cn/news/detail-420674.html
retrievals_all = {'apple': 1, 'banana': 2, 'orange': 3, 'grape': 4, 'kiwi': 5, 'pear': 6}
可以看到,合并后的retrievals_all
字典包含了原始三個字典中的所有鍵值對。如果有重復的鍵,后面的字典會覆蓋前面的字典。最終得到一個包含所有原始字典鍵值對的新字典retrievals_all
。文章來源地址http://www.zghlxwxcb.cn/news/detail-420674.html
到了這里,關(guān)于人工智能中一些看不懂的代碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!