《動(dòng)手學(xué)深度學(xué)習(xí)》第二章地址:https://zh-v2.d2l.ai/chapter_preliminaries/index.html
2.1 練習(xí)
- 運(yùn)行本節(jié)中的代碼辖源。將本節(jié)中的條件語(yǔ)句
X == Y
更改為X < Y
或X > Y
宣渗,然后看看你可以得到什么樣的張量薄霜。
代碼
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
X>Y, X<Y
結(jié)果
(tensor([[False, False, False, False],
[ True, True, True, True],
[ True, True, True, True]]),
tensor([[ True, False, True, False],
[False, False, False, False],
[False, False, False, False]]))
- 用其他形狀(例如三維張量)替換廣播機(jī)制中按元素操作的兩個(gè)張量讶隐。結(jié)果是否與預(yù)期相同伞广?
代碼
a = torch.arange(6).reshape((3, 1, 2))
b = torch.arange(2).reshape((1, 2, 1))
c = a + b
a.shape, b.shape, c.shape
結(jié)果
(torch.Size([3, 1, 2]), torch.Size([1, 2, 1]), torch.Size([3, 2, 2]))
可以看到結(jié)果與預(yù)期相同
2.2 練習(xí)
創(chuàng)建包含更多行和列的原始數(shù)據(jù)集婶博。
生成數(shù)據(jù)
import os
os.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,Size\n') # 列名榔昔,新增一列為Size
f.write('NA,Pave,127500,100\n') # 每行表示一個(gè)數(shù)據(jù)樣本
f.write('2,NA,106000,150\n')
f.write('4,NA,178100,200\n')
f.write('NA,NA,140000,NA\n')
f.write('3,Pave,NA,NA\n') # 新增一行
- 刪除缺失值最多的列蜈项。
代碼
import pandas as pd
data = pd.read_csv(data_file)
data.isna().sum(axis=0) # 查看缺失值最多的列, 缺失值最多的為Alley列
data.drop('Alley', axis=1, inplace=True)
結(jié)果
缺失值個(gè)數(shù)統(tǒng)計(jì):
NumRooms 2
Alley 3
Price 1
Size 2
dtype: int64
刪除缺失值最多的列后的數(shù)據(jù)
NumRooms Price Size
0 NaN 127500.0 100.0
1 2.0 106000.0 150.0
2 4.0 178100.0 200.0
3 NaN 140000.0 NaN
4 3.0 NaN NaN
- 將預(yù)處理后的數(shù)據(jù)集轉(zhuǎn)換為張量格式
預(yù)處理的話聘殖,我們考慮前向后向填充晨雳,將缺失值填補(bǔ)上
代碼
data = data.fillna(method='bfill')
data = data.fillna(method='ffill')
torch.tensor(data.values)
結(jié)果
tensor([[2.0000e+00, 1.2750e+05, 1.0000e+02],
[2.0000e+00, 1.0600e+05, 1.5000e+02],
[4.0000e+00, 1.7810e+05, 2.0000e+02],
[3.0000e+00, 1.4000e+05, 2.0000e+02],
[3.0000e+00, 1.4000e+05, 2.0000e+02]], dtype=torch.float64)
2.3 練習(xí)
- 證明一個(gè)矩陣 的轉(zhuǎn)置的轉(zhuǎn)置是,即 就斤。
對(duì)于中的一個(gè)元素aij悍募,其在第 i 行第 j 列,轉(zhuǎn)置后出現(xiàn)在第 j 行第 i 列洋机,再轉(zhuǎn)置一次就出現(xiàn)在第 i 行第 j 列坠宴,又回到了原來(lái)的位置。所以绷旗,一個(gè)矩陣轉(zhuǎn)置的轉(zhuǎn)置還是它自己喜鼓。
代碼
import numpy as np
A = np.arange(12).reshape(3, 4)
A.T.T == A
結(jié)果
array([[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True]])
- 給出兩個(gè)矩陣 和 ,證明“它們轉(zhuǎn)置的和”等于“它們和的轉(zhuǎn)置”衔肢,即 庄岖。
假設(shè)第 i 行第 j 列的元素是 aij,第 i 行第 j 列的元素是 bij角骤。對(duì)于 隅忿,其第 j 行第 i 列的值為 aij + bij心剥;對(duì)于 ,其第 j 行第 i 列的值也為 aij + bij背桐,推廣至即可知优烧。
代碼
import numpy as np
A = np.arange(12).reshape(3, 4)
B = np.arange(12, 24).reshape(3, 4)
(A.T + B.T) == (A + B).T
結(jié)果
array([[ True, True, True],
[ True, True, True],
[ True, True, True],
[ True, True, True]])
- 給定任意方陣 , 總是對(duì)稱的嗎?為什么?
是的链峭,首先我們看一下對(duì)稱矩陣的概念:
“ 等于其轉(zhuǎn)置:畦娄,則稱為對(duì)稱矩陣”。將 看做一個(gè)整體弊仪,證明如下:
- 我們?cè)诒竟?jié)中定義了形狀 (2,3,4) 的張量熙卡。的輸出結(jié)果是什么?
代碼
X = torch.arange(24).reshape(2, 3, 4)
len(X)
結(jié)果
2
輸出的是0軸的數(shù)值励饵。
- 對(duì)于任意形狀的張量是否總是對(duì)應(yīng)于X特定軸的長(zhǎng)度?這個(gè)軸是什么?
總對(duì)應(yīng)第 0 軸的長(zhǎng)度驳癌,上題已回答。
- 運(yùn)行A/A.sum(axis=1)曲横,看看會(huì)發(fā)生什么喂柒。你能分析原因嗎?
會(huì)出錯(cuò)禾嫉,原因在于A為5行4列的矩陣灾杰,維度為2,而A.sum(axis=1)
則為長(zhǎng)度為5的向量熙参,二者無(wú)法相除艳吠,需要維度一致才會(huì)有廣播機(jī)制,也就是我們需要設(shè)置keepdims=True
- 考慮一個(gè)具有形狀 (2,3,4) 的張量孽椰,在軸0昭娩、1、2上的求和輸出是什么形狀?
課程中已講過(guò)黍匾,對(duì)哪個(gè)軸求和栏渺,可以看作是壓縮該維度,因此
軸0求和——>[3,4]
軸1求和——>[2,4]
軸2求和——>[2,3]
下面用代碼驗(yàn)證一下
代碼
X = torch.arange(24).reshape(2, 3, 4)
X.sum(axis=0).shape, X.sum(axis=1).shape, X.sum(axis=2).shape
結(jié)果
(torch.Size([3, 4]), torch.Size([2, 4]), torch.Size([2, 3]))
- 為linalg.norm函數(shù)提供3個(gè)或更多軸的張量锐涯,并觀察其輸出磕诊。對(duì)于任意形狀的張量這個(gè)函數(shù)計(jì)算得到什么?
計(jì)算得到張量中所有值的 L2范數(shù)。
numpy.linalg.norm
參數(shù)ord
默認(rèn)為None
纹腌,此時(shí)對(duì)應(yīng)的即為L(zhǎng)2范數(shù)霎终,見下表
ord | norm for matrices | norm for vectors |
---|---|---|
None | Frobenius norm | 2-norm |
2.4 練習(xí)
書中的函數(shù)此處不再贅述
- 繪制函數(shù) 和其在 處切線的圖像。
先求導(dǎo)數(shù): 可得時(shí)升薯,莱褒,又因?yàn)?img class="math-inline" src="https://math.jianshu.com/math?formula=f(1)%20%3D%200" alt="f(1) = 0" mathimg="1">
因此切線為
代碼
x = np.arange(0.5, 1.5, 0.01)
plot(x, [x**3 - 1/x, 4*x-4], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)'])
結(jié)果
- 求函數(shù) 的梯度。
- 函數(shù)的梯度是什么涎劈?
先對(duì)求導(dǎo),可得:
同理類推:可得
因此其梯度為:[, 阅茶,……,]
簡(jiǎn)寫為:
- 你可以寫出函數(shù) 炮障,其中 目派,, 的鏈?zhǔn)椒▌t嗎?
2.5 練習(xí)
- 為什么計(jì)算二階導(dǎo)數(shù)比一階導(dǎo)數(shù)的開銷要更大胁赢?
因?yàn)橛?jì)算二階導(dǎo)數(shù)要在一階導(dǎo)數(shù)的基礎(chǔ)上再進(jìn)行求導(dǎo),開銷肯定會(huì)更大白筹。
- 在運(yùn)行反向傳播函數(shù)之后智末,立即再次運(yùn)行它,看看會(huì)發(fā)生什么徒河。
會(huì)發(fā)生運(yùn)行錯(cuò)誤系馆,因?yàn)榍跋蜻^(guò)程建立的計(jì)算圖,會(huì)在反向傳播后釋放顽照,所以第二次運(yùn)行反向傳播就會(huì)出錯(cuò)由蘑。這時(shí)在 backward 函數(shù)中加上參數(shù) retain_graph=True
(保持計(jì)算圖),就能兩次運(yùn)行反向傳播了代兵。
代碼
x = torch.arange(12., requires_grad=True)
y = 2 * torch.dot(x, x)
y.backward()
x.grad # tensor([ 0., 4., 8., 12., 16., 20., 24., 28., 32., 36., 40., 44.])
y.backward() # 會(huì)報(bào)錯(cuò)
- 在控制流的例子中尼酿,我們計(jì)算d關(guān)于a的導(dǎo)數(shù),如果我們將變量a更改為隨機(jī)向量或矩陣植影,會(huì)發(fā)生什么裳擎?
會(huì)發(fā)生運(yùn)行錯(cuò)誤,此處想說(shuō)明的其實(shí)是pytorch中張量無(wú)法對(duì)張量求導(dǎo)思币,只能是標(biāo)量對(duì)張量求導(dǎo)鹿响,因此如果我們將a修改為向量或矩陣,直接backward將會(huì)報(bào)錯(cuò)谷饿,需要對(duì)結(jié)果求和成一個(gè)標(biāo)量后方能求導(dǎo)惶我。
代碼
a = torch.randn(size=(3,1), requires_grad=True)
d = f(a)
d.backward() # 直接運(yùn)行這一步會(huì)報(bào)錯(cuò)
d.sum().backward() # 求和以后運(yùn)行就沒問題了
- 重新設(shè)計(jì)一個(gè)求控制流梯度的例子,運(yùn)行并分析結(jié)果博投。
我們?cè)O(shè)計(jì)一個(gè)范數(shù)如果大于10绸贡,則返回梯度為2,否則返回梯度為1贬堵。以下為代碼和結(jié)果
代碼
def f(a):
if a.norm() > 10:
b = torch.dot(a, a)
else:
b = a
return b.sum()
a1 = torch.arange(12., requires_grad=True)
a2 = torch.arange(2., requires_grad=True)
d1 = f(a1)
d2 = f(a2)
d1.backward()
d2.backward()
a1.grad, a2.grad
結(jié)果
(tensor([ 0., 2., 4., 6., 8., 10., 12., 14., 16., 18., 20., 22.]), # 范數(shù)大于10時(shí)恃轩,梯度為2
tensor([1., 1.])) # 范數(shù)小于10時(shí),梯度為1
- 使 f(x)=sin(x) 黎做,繪制 f(x) 和 df(x)dx 的圖像叉跛,其中后者不使用 f′(x)=cos(x) 。
代碼
x = torch.linspace(-5, 5, 100)
x.requires_grad_(True)
y = torch.sin(x)
y.sum().backward()
y = y.detach()
d2l.plot(x.detach(), [y, x.grad], 'f(x)', "f'(x)", legend=['f(x)', 'Tangent line']) # 不采用cos(x)蒸殿,而使用x.grad
d2l.plt.show()
結(jié)果
2.6 練習(xí)
- 進(jìn)行組實(shí)驗(yàn)筷厘,每組抽取個(gè)樣本鸣峭。改變和,觀察和分析實(shí)驗(yàn)結(jié)果酥艳。
書中已有的結(jié)果,此處將換為充石,換為莫换,查看結(jié)果
代碼
import torch
from torch.distributions import multinomial
from d2l import torch as d2l
fair_probs = torch.ones([6]) / 6
counts = multinomial.Multinomial(20, fair_probs).sample((5000,))
cum_counts = counts.cumsum(dim=0)
estimates = cum_counts / cum_counts.sum(dim=1, keepdims=True)
d2l.set_figsize((6, 4.5))
for i in range(6):
d2l.plt.plot(estimates[:, i].numpy(),
label=("P(die=" + str(i + 1) + ")"))
d2l.plt.axhline(y=0.167, color='black', linestyle='dashed')
d2l.plt.gca().set_xlabel('Groups of experiments')
d2l.plt.gca().set_ylabel('Estimated probability')
d2l.plt.legend()
結(jié)果
m=500,n=10 | m=5000,n=20 |
---|---|
對(duì)比以上結(jié)果可知,第二次的效果更好骤铃,更加趨近于 0.167拉岁。原因可能是第一張圖實(shí)驗(yàn)組數(shù)為 500 組,而第二張圖有 5000 組惰爬,實(shí)驗(yàn)組數(shù)越多喊暖,實(shí)驗(yàn)偏差就會(huì)分布的更加平均,效果就會(huì)更好撕瞧。(此處對(duì)比試驗(yàn)最好將第二張圖的n也設(shè)置為10陵叽,不過(guò)限于篇幅就不再展示了~大家可以下來(lái)多嘗試)
- 給定兩個(gè)概率為的事件丛版,計(jì)算巩掺、的上限和下限。
上限為硼婿,下限為
上限 | 下限 |
---|---|
上限為锌半,下限為
上限 | 下限 |
---|---|
- 假設(shè)我們有一系列隨機(jī)變量,例如 寇漫、 和 刊殉,其中 只依賴于 ,而 只依賴于 州胳,你能簡(jiǎn)化聯(lián)合概率 嗎记焊?
根據(jù)題意可得:滿足馬爾科夫鏈 下面開始推導(dǎo)
其中 =====>馬爾科夫鏈
因此最終化簡(jiǎn)為:
- 在 2.6.2.6節(jié)中,第一個(gè)測(cè)試更準(zhǔn)確栓撞。為什么不運(yùn)行第一個(gè)測(cè)試兩次遍膜,而是同時(shí)運(yùn)行第一個(gè)和第二個(gè)測(cè)試?
原因是如果進(jìn)行兩次第一種測(cè)試,兩次測(cè)試沒有條件獨(dú)立性瓤湘,不能使用上面的公式進(jìn)行計(jì)算瓢颅,而且兩次測(cè)試結(jié)果大概率相同,效果并不好弛说。