在模型訓練或預測時骡苞,我們常常會同時處理多個數據樣本并用到矢量計算啦扬。在介紹線性回歸的矢量計算表達式之前德挣,讓我們先考慮對兩個向量相加的兩種方法臼勉。
[if !supportLists]1.?[endif]向量相加的一種方法是文兢,將這兩個向量按元素逐一做標量加法晤斩。
[if !supportLists]2.?[endif]向量相加的另一種方法是,將這兩個向量直接做矢量加法姆坚。
現在我們可以來測試了澳泵。首先將兩個向量使用for循環(huán)按元素逐一做標量加法。
import?torch
import?time
# init variable a, b as 1000 dimension vector?
n =?1000
a =?torch.ones(n)
b =?torch.ones(n)
# define a timer class to record time?
class?Timer(object):
????"""Record multiple running times."""
????def?__init__(self):
????????self.times =?[]
????????self.start()
????def?start(self):
????????# start the timer
????????self.start_time =?time.time()
????def?stop(self):
????????# stop the timer and record time into a list
????????self.times.append(time.time() -?self.start_time)
????????return?self.times[-1]
????def?avg(self):
????????# calculate the average and return
????????return?sum(self.times)/len(self.times)
????def?sum(self):
????????# return the sum of recorded time
????????return?sum(self.times)
現在我們可以來測試了兼呵。首先將兩個向量使用for循環(huán)按元素逐一做標量加法兔辅。
timer = Timer()
c = torch.zeros(n)
for i in range(n):
c[i] = a[i] + b[i]
'%.5f sec' % timer.stop()
另外是使用torch來將兩個向量直接做矢量加法:
timer.start()
d = a + b
'%.5f sec' % timer.stop()
結果很明顯,后者比前者運算速度更快。因此萍程,我們應該盡可能采用矢量計算幢妄,以提升計算效率。
線性回歸模型從零開始的實現
# import packages and modules
%matplotlib?inline
import?torch
from?IPython?import?display
from?matplotlib?import?pyplot as?plt
import?numpy?as?np
import?random
?
print(torch.__version__)
生成數據集
使用線性模型來生成數據集茫负,生成一個1000個樣本的數據集蕉鸳,下面是用來生成數據的線性關系:
price=warea?area+wage?age+b
# set input feature number
num_inputs =?2
# set example number
num_examples =?1000
?
# set true weight and bias in order to generate corresponded label
true_w =?[2, -3.4]
true_b =?4.2
features =?torch.randn(num_examples, num_inputs,
??????????????????????dtype=torch.float32)
labels =?true_w[0] *?features[:, 0] +?true_w[1] *?features[:, 1] +?true_b
labels +=?torch.tensor(np.random.normal(0, 0.01, size=labels.size()),
???????????????????????dtype=torch.float32)
使用圖像來展示生成的數據
plt.scatter(features[:, 1].numpy(), labels.numpy(), 1);
讀取數據集
def?data_iter(batch_size, features, labels):
????num_examples =?len(features)
????indices =?list(range(num_examples))
????random.shuffle(indices) ?# random read 10 samples
????for?i in?range(0, num_examples, batch_size):
????????j =?torch.LongTensor(indices[i: min(i +?batch_size, num_examples)]) # the last time may be not enough for a whole batch
????????yield??features.index_select(0, j), labels.index_select(0, j)
batch_size =?10
for?X, y in?data_iter(batch_size, features, labels):
????print(X, '\n', y)
????break
初始化模型參數
w =?torch.tensor(np.random.normal(0, 0.01, (num_inputs, 1)), dtype=torch.float32)
b =?torch.zeros(1, dtype=torch.float32)
w.requires_grad_(requires_grad=True)
b.requires_grad_(requires_grad=True)
定義模型
定義用來訓練參數的訓練模型:
price=warea?area+wage?age+b
def?linreg(X, w, b):
????return?torch.mm(X, w) +?b
定義優(yōu)化函數
在這里優(yōu)化函數使用的是小批量隨機梯度下降:
(w,b)←(w,b)?η|B|∑i∈B?(w,b)l(i)(w,b)
def?sgd(params, lr, batch_size):
????for?param in?params:
????????param.data -=?lr *?param.grad /?batch_size
# ues .data to operate param without gradient track
訓練
當數據集、模型忍法、損失函數和優(yōu)化函數定義完了之后就可來準備進行模型的訓練了潮尝。
# super parameters initlr =?0.03num_epochs =?5
net =?linregloss =?squared_loss
# trainingfor?epoch in?range(num_epochs): ?# training repeats num_epochs times
????# in each epoch, all the samples in dataset will be used once
????# X is the feature and y is the label of a batch sample
????for?X, y in?data_iter(batch_size, features, labels):
????????l =?loss(net(X, w, b), y).sum() ?
????????# calculate the gradient of batch sample loss
????????l.backward() ?
????????# using small batch random gradient descent to iter model parameters
????????sgd([w, b], lr, batch_size) ?
????????# reset parameter gradient
????????w.grad.data.zero_()
????????b.grad.data.zero_()
????train_l =?loss(net(features, w, b), labels)
????print('epoch %d, loss %f'?%?(epoch +?1, train_l.mean().item()))
w, true_w, b, true_b
線性回歸模型使用pytorch的簡潔實現
import?torch
from?torch?import?nn
import?numpy?as?np
torch.manual_seed(1)
print(torch.__version__)
torch.set_default_tensor_type('torch.FloatTensor')
生成數據集
在這里生成數據集跟從零開始的實現中是完全一樣的。
num_inputs =?2
num_examples =?1000
true_w =?[2, -3.4]
true_b =?4.2
features =?torch.tensor(np.random.normal(0, 1, (num_examples, num_inputs)), dtype=torch.float)
labels =?true_w[0] *?features[:, 0] +?true_w[1] *?features[:, 1] +?true_b
labels +=?torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float)
讀取數據集
import?torch.utils.data?as?Data
batch_size =?10
# combine featues and labels of dataset
dataset =?Data.TensorDataset(features, labels)
# put dataset into DataLoader
data_iter =?Data.DataLoader(
????dataset=dataset, ???????????# torch TensorDataset format
????batch_size=batch_size, ?????# mini batch size
????shuffle=True, ??????????????# whether shuffle the data or not
num_workers=2, ?????????????# read data in multithreading
)
for?X, y in?data_iter:
????print(X, '\n', y)
????break
定義模型
class?LinearNet(nn.Module):
????def?__init__(self, n_feature):
????????super(LinearNet, self).__init__() ?????# call father function to init
????????self.linear =?nn.Linear(n_feature, 1) ?# function prototype: `torch.nn.Linear(in_features, out_features, bias=True)`
????def?forward(self, x):
????????y =?self.linear(x)
????????return?y
net =?LinearNet(num_inputs)print(net)
# ways to init a multilayer network# method onenet =?nn.Sequential(
????nn.Linear(num_inputs, 1)
????# other layers can be added here
????)
# method tw
net =?nn.Sequential()net.add_module('linear', nn.Linear(num_inputs, 1))
# net.add_module ......
# method three
from?collections?import?OrderedDict
net =?nn.Sequential(OrderedDict([
??????????('linear', nn.Linear(num_inputs, 1))
??????????# ......
????????]))
print(net)
print(net[0])
初始化模型參數
In?[22]:
from?torch.nn?import?init
init.normal_(net[0].weight, mean=0.0, std=0.01)
init.constant_(net[0].bias, val=0.0) ?# or you can use `net[0].bias.data.fill_(0)` to modify it directly
In?[23]:
for?param in?net.parameters():
????print(param)
定義損失函數
In?[24]:
loss =?nn.MSELoss() ???# nn built-in squared loss function
???????????????????????# function prototype: `torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')`
定義優(yōu)化函數
In?[25]:
import?torch.optim?as?optim
optimizer =?optim.SGD(net.parameters(), lr=0.03) ??# built-in random gradient descent function
print(optimizer) ?# function prototype: `torch.optim.SGD(params, lr=, momentum=0, dampening=0, weight_decay=0, nesterov=False)`
訓練
In?[26]:
num_epochs =?3
for?epoch in?range(1, num_epochs +?1):
????for?X, y in?data_iter:
????????output =?net(X)
????????l =?loss(output, y.view(-1, 1))
????????optimizer.zero_grad() # reset gradient, equal to net.zero_grad()
????????l.backward()
????????optimizer.step()
????print('epoch %d, loss: %f'?%?(epoch, l.item()))
In?[27]:
# result comparision
dense =?net[0]
print(true_w, dense.weight.data)
print(true_b, dense.bias.data)
2.補充:【numpy庫函數】reshape用法饿序,包含-1這個參數
(原帖:https://blog.csdn.net/qq_37791134/article/details/90543879)
numpy.reshape(重塑):給數組一個新的形狀而不改變其數據
numpy.reshape(a, newshape, order=’C’)
參數:
[if !supportLists]1.?[endif]a:array_like
要重新形成的數組勉失。
[if !supportLists]2.?[endif]newshape:int或tuple的整數
新的形狀應該與原始形狀兼容。如果是整數原探,則結果將是該長度的1-D數組乱凿。一個形狀維度可以是-1。在這種情況下咽弦,從數組的長度和其余維度推斷該值徒蟆。
[if !supportLists]3.?[endif]order:{'C','F'型型,'A'}可選
使用此索引順序讀取a的元素段审,并使用此索引順序將元素放置到重新形成的數組中。'C'意味著使用C樣索引順序讀取/寫入元素闹蒜,最后一個軸索引變化最快寺枉,回到第一個軸索引變化最慢。'F'意味著使用Fortran樣索引順序讀取/寫入元素绷落,第一個索引變化最快姥闪,最后一個索引變化最慢。注意砌烁,'C'和'F'選項不考慮底層數組的內存布局筐喳,而只是參考索引的順序。'A'意味著在Fortran類索引順序中讀/寫元素,如果a 是Fortran 在內存中連續(xù)的疏唾,否則為C樣順序。
注意:newshape : int or tuple of ints
大意是說函似,數組新的shape屬性應該要與原來的配套槐脏,如果等于-1的話,那么Numpy會根據剩下的維度計算出數組的另外一個newshape屬性值撇寞。?
舉例:有一個數組z顿天,它的shape屬性是(4, 4)?
z = np.array([[1, 2, 3, 4],?
[5, 6, 7, 8],?
[9, 10, 11, 12],?
[13, 14, 15, 16]])?
z.shape?
(4, 4)?
z.reshape(-1)?
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
z.reshape(-1, 1),是說蔑担,我們不知道新z的行數是多少牌废,但是想讓z變成只有一列,行數不知的新數組啤握,通過z.reshape(-1,1)鸟缕,Numpy自動計算出有12行,新的數組shape屬性為(16, 1)排抬,與原來的(4, 4)配套懂从。z.reshape(-1,1)?
array([[ 1],?
[ 2],?
[ 3],?
[ 4],?
[ 5],?
[ 6],?
[ 7],?
[ 8],?
[ 9],?
[10],?
[11],?
[12],?
[13],?
[14],?
[15],?
[16]])
z.reshape(-1, 2),行數未知蹲蒲,列數等于2番甩,reshape后的shape等于(8, 2)?
z.reshape(-1, 2)?
array([[ 1, 2],?
[ 3, 4],?
[ 5, 6],?
[ 7, 8],?
[ 9, 10],?
[11, 12],?
[13, 14],?
[15, 16]])
同理,只給定行數届搁,列數未知缘薛,也可以設置newshape等于-1,Numpy也可以自動計算出新數組的列數卡睦。
[if !supportLists]4.?[endif]最?似然估計與最小化交叉熵損失函數
(https://blog.csdn.net/zgcr654321/article/details/85204049)
似然的概念:“似然”用通俗的話來說就是可能性宴胧,極大似然就是最大的可能性。
似然函數:似然函數是關于統計模型中的一組概率的函數(這些概率的真實值我們并不知道)么翰,似然函數的因變量值表示了模型中的概率參數的似然性(可能性)牺汤。
最大似然估計:我們列出似然函數后,從真實事件中取得一批n個采樣樣本數據浩嫌,最大似然估計會尋找基于我們的n個值的采樣數據得到的關于的最可能的概率值(即在所有可能的概率取值中檐迟,尋找一組概率值使這n個值的采樣數據的“可能性”最大化)。
最大似然估計中采樣需滿足一個很重要的假設码耐,就是所有的采樣都是獨立同分布的追迟。
伯努利分布:伯努利分布又名兩點分布或0-1分布,介紹伯努利分布前首先需要引入伯努利試驗骚腥。
伯努利試驗是只有兩種可能結果的單次隨機試驗敦间,即對于一個隨機變量X而言:
P(X=1)=p
P(X=0)=1?p
伯努利試驗可以表達為“是或否”的問題。
如果試驗E是一個伯努利試驗,將E獨立重復地進行n次廓块,則稱這一串重復的獨立試驗為n重伯努利試驗厢绝。
進行一次伯努利試驗,成功概率為p带猴,失敗概率為1-p昔汉,則稱隨機變量X服從伯努利分布。
其概率質量函數為:
伯努利分布的
伯努利分布是一個離散型機率分布拴清,是N=1時二項分布的特殊情況靶病。
伯努利分布下的最大似然估計推導出交叉熵損失函數:
假設
P(X=1)=p,P(X=0)=1?p
則有概率質量函數為
因為我們只有一組采樣數據集D,我們可以統計得到X和1-X的值口予,但p值(概率)未知娄周。下面我們要建立對數似然函數,并根據采樣數據集D求出P沪停。
對數似然函數為:
我們可以發(fā)現上式和深度學習模型中交叉熵損失函數的形式幾乎相同煤辨。這個函數的值總是小于0的,而我們要做極大似然估計就是求其極大值牙甫,也就是說掷酗,這個函數的值在深度學習的梯度下降過程中從一個負數不斷增大接近0(始終小于0)。為了與其他損失函數形式統一窟哺,我們在前面加上一個負號泻轰,這樣就和其他損失函數一樣是從一個大值不斷降低向0接近了。
深度學習模型中的交叉熵函數形式:
現在我們再用求導得極小值點的方法來求其極大似然估計且轨,首先將上式對p求導浮声,并令導數為0。
?
消去分母旋奢,得:
這就是伯努利分布下最大似然估計求出的P泳挥。