醫(yī)學(xué)院英文網(wǎng)站建設(shè)方案廣州網(wǎng)絡(luò)推廣哪家好
數(shù)據(jù)操作
機(jī)器學(xué)習(xí)包括的核心組件有:
- 可以用來(lái)學(xué)習(xí)的數(shù)據(jù)(data);
- 如何轉(zhuǎn)換數(shù)據(jù)的模型(model);
- 一個(gè)目標(biāo)函數(shù)(objective function),用來(lái)量化模型的有效性;
- 調(diào)整模型參數(shù)以優(yōu)化目標(biāo)函數(shù)的算法(algorithm)。
我們要從數(shù)據(jù)中提取出特征,機(jī)器學(xué)習(xí)、深度學(xué)習(xí)通過(guò)特征來(lái)進(jìn)一步計(jì)算得到模型。因此下面主要介紹的是對(duì)數(shù)據(jù)要做哪些操作。
基本操作
深度學(xué)習(xí)里最多操作的數(shù)據(jù)結(jié)構(gòu)是N維的數(shù)組。
0維:一個(gè)數(shù),一個(gè)標(biāo)量,比如1.
1維:比如一個(gè)一維數(shù)組,他的數(shù)據(jù)是一個(gè)一維的向量(特征向量)。
2維:比如二維數(shù)組(特征矩陣)。
當(dāng)然還有更多維度,比如視頻的長(zhǎng),寬,時(shí)間,批量大小,通道……
如果我們想創(chuàng)建這樣一個(gè)數(shù)組,需要明確的因素:
- 數(shù)組結(jié)構(gòu),比如3*4.
- 數(shù)組數(shù)據(jù)類型,浮點(diǎn)?整形?
- 具體每個(gè)元素的值。
訪問(wèn)元素的方式:
1:3 是左閉右開(kāi),表示不包含第3行。
雙冒號(hào)是跳著訪問(wèn),后跟步長(zhǎng)。比如 ::3 表示從第0行開(kāi)始訪問(wèn),每3行訪問(wèn)一次。
明白了這些,那接下來(lái)我們就創(chuàng)建一個(gè)數(shù)組。在機(jī)器學(xué)習(xí)中這種數(shù)據(jù)的容器一般被稱作張量.
創(chuàng)建張量
這部分代碼在 jupyter/pytorch/chapter_preliminaries/ndarray.ipynb
里。
在其中可以運(yùn)行嘗試代碼部分,創(chuàng)建一維張量:
import torch
X = torch.arange(12) # 自動(dòng)創(chuàng)建 0-11 的一維張量。輸入 X 查看 X 內(nèi)元素?cái)?shù)據(jù),輸出:
# tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
X.shape # 查看向量形狀。輸出 torch.Size([12]),指長(zhǎng)12的一維向量
X.numel() # 只獲取長(zhǎng)度,輸出12
X = X.reshape(3, 4) # 重新改成了3行4列形狀。變成了0123 4567 891011
torch.zeros((2, 3, 4)) # 創(chuàng)建了一個(gè)形狀為(2,3,4)的全0張量
# tensor([[[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]],
#
# [[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]]])
# torch.ones 同理,是全1的
# torch.randn 是取隨機(jī)數(shù),隨機(jī)數(shù)是均值=0,方差=1的一個(gè)高斯分布中取
torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) # 給定值創(chuàng)建
torch.exp(X) # 求e^x中每個(gè)元素值得到的新張量
reshape 很有意思,它不是復(fù)制原數(shù)組后重新開(kāi)辟了一片空間,而是還是對(duì)原數(shù)組元素的操作(只不過(guò)原來(lái)是連續(xù)12個(gè)數(shù),現(xiàn)在我們把他們視作4個(gè)一行的3行元素。存儲(chǔ)空間都是連續(xù)的)。因此如果我們對(duì) reshape 后的數(shù)組賦值,原數(shù)組值也會(huì)改變。
算術(shù)運(yùn)算
對(duì)于兩個(gè)相同形狀的向量可以進(jìn)行+ - * / **(求冪運(yùn)算)運(yùn)算。
x = torch.tensor([1.0, 2, 4, 8]) # 1.0 為了讓這個(gè)數(shù)組變成浮點(diǎn)數(shù)組
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x ** y # **運(yùn)算符是求冪運(yùn)算
# Output:
(tensor([ 3., 4., 6., 10.]),tensor([-1., 0., 2., 6.]),tensor([ 2., 4., 8., 16.]),tensor([0.5000, 1.0000, 2.0000, 4.0000]),tensor([ 1., 4., 16., 64.]))
x==y # 每一項(xiàng)分別判斷是否相等。我試了一下,數(shù)據(jù)類型不影響。2.0==2
x.sum() # 所有元素求和
張量連接
X = torch.arange(12, dtype=torch.float32).reshape((3,4)) # 創(chuàng)建 float32 位的張量
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1) # 行和列兩個(gè)維度的拼接
# Output:
(tensor([[ 0., 1., 2., 3.],[ 4., 5., 6., 7.],[ 8., 9., 10., 11.],[ 2., 1., 4., 3.],[ 1., 2., 3., 4.],[ 4., 3., 2., 1.]]),tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.],[ 4., 5., 6., 7., 1., 2., 3., 4.],[ 8., 9., 10., 11., 4., 3., 2., 1.]]))
# 這里我看到彈幕前輩的講解,感覺(jué)很受用。行是樣例,列是特征屬性,這個(gè)類似 MySQL 的關(guān)系數(shù)據(jù)庫(kù)理解
廣播機(jī)制
即使兩個(gè)張量形狀不同,也有可能通過(guò)廣播機(jī)制進(jìn)行按元素操作。
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a, b
# Output:
(tensor([[0],[1],[2]]),tensor([[0, 1]]))a + b # 把a(bǔ)按列復(fù)制2份,b按行復(fù)制3份,都變成3*2的張量進(jìn)行操作
# Output:
tensor([[0, 1],[1, 2],[2, 3]])
索引
X[-1], X[1:3] # 這里和前面介紹的概念一樣。-1 是倒數(shù)第一個(gè)元素(一個(gè)n-1維度張量),1:3 是第2,第3個(gè)元素不包括第4個(gè)元素。
# Output:
(tensor([ 8., 9., 10., 11.]),tensor([[ 4., 5., 6., 7.],[ 8., 9., 10., 11.]]))
X[1,2]=9 # 寫(xiě)入
X[0:2, :] = 12 # 批量寫(xiě)入,給0-1行,所有列寫(xiě)成12
X
# Output:
tensor([[12., 12., 12., 12.],[12., 12., 12., 12.],[ 8., 9., 10., 11.]])
節(jié)省內(nèi)存
有一些操作會(huì)分配新內(nèi)存。比如 Y=Y+X,并不是直接在 Y 的原地址上加了X,而是在新地址上計(jì)算得到 Y+X,讓 Y 指向新地址。
可以通過(guò) id(X)
函數(shù)來(lái)查看地址。
Y[:]=Y+X
或者 Y+=X
會(huì)在原地執(zhí)行計(jì)算,Y 地址不變。
類型轉(zhuǎn)換
轉(zhuǎn)換為 numpy 張量:A=X.numpy()
張量轉(zhuǎn)換為標(biāo)量:
a=torch.tensor([3.5])
a.item() # 3.5
float(a) # 3.5
int(a) # 3
數(shù)據(jù)預(yù)處理
實(shí)際處理數(shù)據(jù)的時(shí)候我們并不是從張量數(shù)據(jù)類型開(kāi)始的,我們可能得到一個(gè) excel 文件,自己把它轉(zhuǎn)換成 python 張量。以及在轉(zhuǎn)換之前,我們可能對(duì)數(shù)據(jù)進(jìn)行預(yù)處理,比如把其中的空值統(tǒng)一賦值為0之類的操作。以下是轉(zhuǎn)換步驟。
首先我們創(chuàng)建一個(gè) csv 文件作為原始數(shù)據(jù)集。
import osos.makedirs(os.path.join('..', 'data'), exist_ok=True)
data_file = os.path.join('..', 'data', 'house_tiny.csv')
with open(data_file, 'w') as f:f.write('NumRooms,Alley,Price\n') # 列名f.write('NA,Pave,127500\n') # 每行表示一個(gè)數(shù)據(jù)樣本f.write('2,NA,106000\n')f.write('4,NA,178100\n')f.write('NA,NA,140000\n')
三個(gè)屬性分別是 room 數(shù)量,走廊狀態(tài)(比如鋪了地板),價(jià)格。
然后我們把這個(gè)數(shù)據(jù)讀入 python,加載原始數(shù)據(jù)集。
# 如果沒(méi)有安裝pandas,只需取消對(duì)以下行的注釋來(lái)安裝pandas
# !pip install pandas
import pandas as pddata = pd.read_csv(data_file)
這個(gè)數(shù)據(jù)集里還是有很多 NaN 項(xiàng)的,我們要對(duì)其進(jìn)行修改替換。數(shù)值類典型處理方式是插值和刪除。
首先最后一列數(shù)據(jù)是完整不需要修改的,那么我們只要處理前兩列,我們把前兩列數(shù)據(jù)單獨(dú)拿出來(lái)做完處理最后進(jìn)行張量拼接。
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
然后我們把 NumEooms 中的 NaN 值用均值替代,
inputs = inputs.fillna(inputs.mean(numeric_only=True))
print(inputs)
# Output:NumRooms Alley
0 3.0 Pave
1 2.0 NaN
2 4.0 NaN
3 3.0 NaN
對(duì)于 Alley 列,只有兩種狀態(tài):NaN 和 Pave。我們用 pandas 的方法,把 NaN 也視作一個(gè)類,自動(dòng)拆成兩列設(shè)置值。
inputs = pd.get_dummies(inputs, dummy_na=True)
print(inputs)
# Output:NumRooms Alley_Pave Alley_nan
0 3.0 1 0
1 2.0 0 1
2 4.0 0 1
3 3.0 0 1
最后,我們將前兩列處理后得到的結(jié)果與最后一列轉(zhuǎn)換為張量后進(jìn)行拼接。
import torchX = torch.tensor(inputs.to_numpy(dtype=float))
y = torch.tensor(outputs.to_numpy(dtype=float))
y=y.reshape(4,1)
torch.cat((X,y),dim=1)
# Output:
tensor([[3.0000e+00, 1.0000e+00, 0.0000e+00, 1.2750e+05],[2.0000e+00, 0.0000e+00, 1.0000e+00, 1.0600e+05],[4.0000e+00, 0.0000e+00, 1.0000e+00, 1.7810e+05],[3.0000e+00, 0.0000e+00, 1.0000e+00, 1.4000e+05]], dtype=torch.float64)