線性迴歸的從零實現(藉助pytorch)
阿新 • • 發佈:2021-12-14
import torch from torch import nn import random net=nn.Linear(2,1) print(net.type) print(torch.__version__) za=[3,4,5,6,7,8,9,10] random.shuffle(za)#把za打亂順序 bt=torch.tensor(za[1:7]) mt=list(range(20)) mt=torch.tensor(mt)#注意此處只有轉化為torch.tensor()後 #才能在後續的mt(bt執行) print(bt,bt.type()) print(mt,type(mt)) print(mt[bt])#可繼續參考下面模組的程式碼
# %matplotlib inline #顯示圖示預設嵌入jupyter notebook中來顯示 import random import torch from d2l import torch as d2l #import d2lzh_pytorch as d2l #有網友這樣說 #如果沒有d2l可以用pip安裝,或者在jupyter notebook中安裝的話用!pip install d2l命令安裝
''' torch.normal(A, B ,size(C, D), requires_grad=True) A表示均值,B表示標準差 ,C代表生成的資料行數,D表示列數,requires_grad=True表示對導數開始記錄,不需要記錄的話可以忽略。 ''' def synthetic_data(w,b,num_examples): """生成y=Xw+b+噪聲""" X=torch.normal(0,1,(num_examples,len(w)))#X為1000行2列的矩陣,0是均值,1是標準差。 y=torch.matmul(X,w)+b#X與w相乘,並加上b,可以用廣播機制來加b,結果是1000行1列的列向量矩陣 y+=torch.normal(0,0.01,y.shape) # print(y.shape,y.reshape(-1,1).shape)#torch.Size([1000]),torch.Size([1000, 1])說明y本身就是一個列向量,reshape(-1,1)後變成了若干行1列的二維矩陣 # print(y.shape,y.shape[0],sep='\n')#torch.Size([1000]),1000,如果是y.shape[1]就報錯了,因為y只有行這個維度。 # print(y.size())#torch.Size([1000]) # print(y.reshape(-1,1).shape)#torch.Size([1000, 1]) # print(y.reshape((-1,1)).shape)#torch.Size([1000, 1]) return X,y.reshape((-1,1)) true_w=torch.tensor([2,-3.4]) #true_w是個2行1列的矩陣,是個列向量 true_b=4.2 features,labels=synthetic_data(true_w,true_b,1000) # print(len(features),len(labels)) print(features.shape,labels.shape)
print('features:',features[0],'\nlabel:',labels[0])
d2l.set_figsize() d2l.plt.scatter(features[:,1].detach().numpy(),labels.detach().numpy(),1)
'''每次從所給的樣本中選取batch個''' def data_iter(batch_size,features,labels): num_examples=len(features) indices=list(range(num_examples)) #這些樣本是隨機讀取的,沒有特定的順序 random.shuffle(indices)#打亂順序後得到一個有打亂下標的list for i in range(0,num_examples,batch_size): '''此為構造一個隨機樣本,把樣本的順序打亂,然後間隔相同訪問,來達到隨機的目的''' batch_indices=torch.tensor(indices[i:min(i+batch_size,num_examples)]) yield features[batch_indices],labels[batch_indices] batch_size=10 for X,y in data_iter(batch_size,features,labels): print(X,'\n',y) break
num_examples=15 indices=list(range(15)) #這些樣本是隨機讀取的,沒有特定的順序 random.shuffle(indices) for i in range(0,15,10): batch_indices=torch.tensor(indices[i:min(i+10,15)]) print(batch_indices) w=torch.normal(0,0.01,size=(2,1),requires_grad=True) b=torch.ones(1,requires_grad=True) def linreg(X,w,b): """線性迴歸模型""" return torch.matmul(X,w)+b # print(w.size(),w.shape)
def squared_loss(y_hat,y): "均方誤差" return (y_hat-y.reshape(y_hat.shape))**2/2
def sgd(params,lr,batch_size):#params裡面包括w和b引數 """小批量隨機梯度下降""" with torch.no_grad(): for param in params: param-=lr*param.grad/batch_size#這個param又可能是w,也有可能是b; #此處的除以batch_size.是因為之前的loss沒有求均值,此處求均值。因為乘法對梯度來說是一個線性關係, #所以,除以batch_size除在上面和下面效果一樣。也因為我們計算的梯度是一個批量樣本的總和,所以用批量大小 #來歸一化步長,這樣步長就不會取決於我們對批量大小的選擇。 param.grad.zero_()#pytorch會不斷累加變數的梯度,故每更新一次引數,就要讓其對應的梯度清零。
lr=0.03 num_epochs=3 net=linreg loss=squared_loss for epoch in range(num_epochs): for X,y in data_iter(batch_size,features,labels): l=loss(net(X,w,b),y)#X和y的小批量損失 #因為1 形狀是(batch_size,1),而不是一個標量。1中的所有元素被加到 #並一次計算關於[w,b]的梯度 l.sum().backward()#求和之後算梯度;求和本身讓l以標量的形式變現出來;求梯度對於l中的每一個分量都是單獨求的; #求和之後後面會除batch_size可以計算均值。因為向量求梯度得矩陣;要同通過sum()轉化為標量,然後再求梯度。 #不求和的話是個向量,梯度算下來就變成矩陣了,形狀沒法對應。這裡點backward()之後,你在sgd優化演算法裡就可以用 #相應引數的點grad計算。 sgd([w,b],lr,batch_size)#使用引數的梯度更新引數 with torch.no_grad(): train_l=loss(net(features,w,b),labels) print(f'epoch{epoch+1},loss{float(train_l.mean()):f}')
print('w的估計誤差:{}'.format({true_w-w.reshape(true_w.shape)})) print('b的估計誤差:{}'.format({true_b-b}))
python列印的時候print(f"*******") 的括號裡的 f' ' 的意思 ?
python的print字串前面加f表示格式化字串,加f後可以在字串裡面使用用花括號括起來的變數和表示式,如果字串裡面沒有表示式,那麼前面加不加f輸出應該都一樣.Python3.6新增了一種f-字串格式化.
格式化的字串文字字首為’f’和接受的格式字串相似str.format()。它們包含由花括號包圍的替換區域。替換欄位是表示式,在執行時進行評估,然後使用format()協議進行格式化。
formatted string literals, 以 f 開頭,包含的{}表示式在程式執行時會被表示式的值代替。