<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          從零實現(xiàn)深度學習框架(十一)從零實現(xiàn)線性回歸

          共 8109字,需瀏覽 17分鐘

           ·

          2022-01-11 12:34

          更多精彩推薦,請關注我們


          引言

          本著“凡我不能創(chuàng)造的,我就不能理解”的思想,本系列文章會基于純Python以及NumPy從零創(chuàng)建自己的深度學習框架,該框架類似PyTorch能實現(xiàn)自動求導。

          要深入理解深度學習,從零開始創(chuàng)建的經驗非常重要,從自己可以理解的角度出發(fā),盡量不適用外部完備的框架前提下,實現(xiàn)我們想要的模型。本系列文章的宗旨就是通過這樣的過程,讓大家切實掌握深度學習底層實現(xiàn),而不是僅做一個調包俠。

          上篇文章中,我們了解了線性回歸。本文就來通過metagrad實現(xiàn)線性回歸。

          實現(xiàn)模型基類

          class?Module:
          ????'''
          ????所有模型的基類
          ????'''


          ????def?parameters(self)?->?List[Parameter]:
          ????????parameters?=?[]
          ????????for?name,?value?in?inspect.getmembers(self):
          ????????????if?isinstance(value,?Parameter):
          ????????????????parameters.append(value)
          ????????????elif?isinstance(value,?Module):
          ????????????????parameters.extend(value.parameters())

          ????????return?parameters

          ????def?zero_grad(self):
          ????????for?p?in?self.parameters():
          ????????????p.zero_grad()

          ????def?__call__(self,?*args,?**kwargs):
          ????????return?self.forward(*args,?**kwargs)

          ????def?forward(self,?*args,?**kwargs)?->?Tensor:
          ????????raise?NotImplementedError

          類似PyTorch,我們也實現(xiàn)一個模型的基類,其中存放一些通用方法。代碼如上。主要實現(xiàn)了梯度清零方法。

          其中Parameter的定義如下:

          class?Parameter(Tensor):
          ????def?__init__(self,?data:?Union[Arrayable,?Tensor])?->?None:
          ????????
          ????????if?isinstance(data,?Tensor):
          ????????????data?=?data.data
          ????????#?Parameter都是需要計算梯度的
          ????????super().__init__(data,?requires_grad=True)

          Parameter默認需要計算梯度,在Moduleparameters()方法中利用Parameter類獲取模型的所有參數(shù)。

          實現(xiàn)線性回歸

          class?Linear(Module):
          ????r"""
          ?????????對給定的輸入進行線性變換:?:math:`y=xA^T?+?b`

          ????????Args:
          ????????????in_features:?每個輸入樣本的大小
          ????????????out_features:?每個輸出樣本的大小
          ????????????bias:?是否含有偏置,默認?``True``
          ????????Shape:
          ????????????-?Input:?`(*,?H_in)`?其中?`*`?表示任意維度,包括none,這里?`H_{in}?=?in_features`
          ????????????-?Output:?:math:`(*,?H_out)`?除了最后一個維度外,所有維度的形狀都與輸入相同,這里H_out?=?out_features`
          ????????Attributes:
          ????????????weight:?可學習的權重,形狀為?`(out_features,?in_features)`.
          ????????????bias:???可學習的偏置,形狀?`(out_features)`.
          ????????"""


          ????def?__init__(self,?in_features:?int,?out_features:?int,?bias:?bool?=?True)?->?None:
          ????????self.in_features?=?in_features
          ????????self.out_features?=?out_features

          ????????self.weight?=?Parameter(Tensor.empty((out_features,?in_features)))
          ????????if?bias:
          ????????????self.bias?=?Parameter(Tensor.zeros(out_features))
          ????????else:
          ????????????self.bias?=?None
          ????????self.reset_parameters()

          ????def?reset_parameters(self)?->?None:
          ????????self.weight.assign(np.random.randn(self.out_features,?self.in_features))

          ????def?forward(self,?input:?Tensor)?->?Tensor:
          ????????x?=?input?@?self.weight.T
          ????????if?self.bias?is?not?None:
          ????????????x?=?x?+?self.bias

          ????????return?x

          讓我們的線性回歸模型繼承Module,同時定義權重和偏置大小。最后我們只需要實現(xiàn)前向傳播算法,反向傳播就交給我們的自動求導機制去完成。

          這樣,我們的線性回歸模型就實現(xiàn)完成了。但為了我們的模型能夠學習,我們需要定義損失函數(shù)。

          實現(xiàn)損失基類

          class?_Loss(Module):
          ????'''
          ????損失的基類
          ????'''

          ????reduction:?str??#?none?|?mean?|?sum

          ????def?__init__(self,?reduction:?str?=?"mean")?->?None:
          ????????self.reduction?=?reduction

          參考了PyTorch,聚合方法支持均值和求和。

          實現(xiàn)均方誤差

          class?MSELoss(_Loss):
          ????def?__init__(self,?reduction:?str?=?"mean")?->?None:
          ????????'''
          ????????均方誤差
          ????????'''

          ????????super().__init__(reduction)

          ????def?forward(self,?input:?Tensor,?target:?Tensor)?->?Tensor:
          ????????assert?input.size?==?target.size,?f"Using?a?target?size?({target.size})?that?is?different?to?the?input?size?"?\
          ???????????????????????????????????????????f"({input.size}).?This?will?likely?lead?to?incorrect?results?due?to?"?\
          ???????????????????????????????????????????f"broadcasting.?Please?ensure?they?have?the?same?size."

          ????????errors?=?(input?-?target)?**?2
          ????????if?self.reduction?==?"mean":
          ????????????loss?=?errors.sum(keepdims=False)?/?len(input)
          ????????elif?self.reduction?==?"sum":
          ????????????loss?=?errors.sum(keepdims=False)
          ????????else:
          ????????????loss?=?errors

          ????????return?loss

          這里的input其實是模型的輸出,target真實輸出。

          有了損失函數(shù)后,我們還需要優(yōu)化方法來進行參數(shù)優(yōu)化。

          實現(xiàn)優(yōu)化方法

          class?Optimizer:
          ????def?__init__(self,?params:?List[Parameter])?->?None:
          ????????self.params?=?params

          ????def?zero_grad(self)?->?None:
          ????????for?p?in?self.params:
          ????????????p.zero_grad()

          ????def?step(self)?->?None:
          ????????raise?NotImplementedError

          我們如上實現(xiàn)了優(yōu)化方法的基類。下面就是實現(xiàn)隨機梯度下降法(SGD)。

          實現(xiàn)隨機梯度下降法

          class?SGD(Optimizer):
          ????'''
          ????隨機梯度下降
          ????'''


          ????def?__init__(self,?params:?List[Parameter],?lr:?float?=?1e-3)?->?None:
          ????????super().__init__(params)
          ????????self.lr?=?lr

          ????def?step(self)?->?None:
          ????????for?p?in?self.params:
          ????????????p?-=?p.grad?*?self.lr

          lr是學習率,每次調用step()都會進行參數(shù)更新。

          線性回歸實例

          我們基于上篇文章中采集的深圳市南山區(qū)臨近地鐵口二手房價的數(shù)據(jù)為例:

          #?面積
          areas?=?[64.4,?68,?74.1,?74.,?76.9,?78.1,?78.6]
          #?掛牌售價
          prices?=?[6.1,?6.25,?7.8,?6.66,?7.82,?7.14,?8.02]

          我們先考慮面積和掛牌價(可能是指導價 ?單位:萬/㎡)之間的關系。

          面積和售價的關系

          看上去似乎有一定的線性關系。我們這里簡單的考慮套內面積,實際上我們買房時還會考慮房齡、離地鐵口距離、小區(qū)周邊環(huán)境、空氣質量、小區(qū)綠化區(qū)面積等。

          這里我們嘗試通過畫一條直線,使得該直線盡可能和每個樣本的距離最短。

          #?!pip?install?git+https://github.com/nlp-greyfoss/metagrad.git?--upgrade
          from?metagrad.loss?import?MSELoss
          from?metagrad.module?import?Linear
          from?metagrad.optim?import?SGD
          from?metagrad.tensor?import?Tensor

          model?=?Linear(1,?1)

          optimizer?=?SGD(model.parameters(),?lr=1e-1)

          loss?=?MSELoss()

          #?面積
          areas?=?[64.4,?68,?74.1,?74.,?76.9,?78.1,?78.6]
          #?掛牌售價
          prices?=?[6.1,?6.25,?7.8,?6.66,?7.82,?7.14,?8.02]

          X?=?Tensor(areas).reshape((-1,?1))
          y?=?Tensor(prices).reshape((-1,?1))

          epochs?=?100
          losses?=?[]
          for?epoch?in?range(epochs):
          ??l?=?loss(model(X),?y)
          ??optimizer.zero_grad()
          ??l.backward()
          ??optimizer.step()
          ??epoch_loss?=?l.data
          ??
          ??losses.append(epoch_loss)

          ??print(f'epoch?{epoch?+?1},?loss?{float(epoch_loss):f}')

          上面就是通過我們自己的metagrad實現(xiàn)的線性回歸學習過程,是不是看上去有那味了。

          輸出:

          epoch?1,?loss?198.071304
          epoch?2,?loss?232059248.000000
          epoch?3,?loss?272126879727616.000000
          epoch?4,?loss?319112649512125988864.000000
          epoch?5,?loss?374211056107641585692311552.000000
          epoch?6,?loss?438822818730812850430760481456128.000000
          epoch?7,?loss?inf
          ...

          怎么損失不降反增了!?

          莫慌,我們只有一個變量,不存在兩個變量的量綱不同的問題。此時,該顯示一下我們AI調參師的技術了。

          損失太大,可能是梯度太大了,我們直接將學習率調小。

          optimizer?=?SGD(model.parameters(),?lr=1e-4)

          我們修改學習率為1e-4

          epoch?1,?loss?21798.214844
          epoch?2,?loss?153.602646
          epoch?3,?loss?1.260477
          epoch?4,?loss?0.188241
          epoch?5,?loss?0.180694
          epoch?6,?loss?0.180641
          epoch?7,?loss?0.180641
          epoch?8,?loss?0.180641
          epoch?9,?loss?0.180641
          epoch?10,?loss?0.180641
          epoch?11,?loss?0.180641
          epoch?12,?loss?0.180640
          ...
          epoch?99,?loss?0.180638
          epoch?100,?loss?0.180638

          從輸出可以看出,第4次迭代后,損失就一直不變了,我們看一下學習率曲線:

          學習率曲線

          我們可以打印出得到的參數(shù):

          >?w,?b?=?model.weight.data.item(),model.bias.data.item()
          >?print(f'w:?{w},?b:{b}')
          w:?0.09660441144108287,?b:0.026999891111711846

          然后畫出線性回歸擬合的直線:

          預測直線

          看上去還可以,如果你要買房的話,建議你買直線下面的房子。

          基于我們這點訓練樣本,得到最后的損失為,我們能否使它再次降低呢?

          一種方法是收集更多的數(shù)據(jù),另一種方法是利用所有的維度。我們還有一個房齡維度沒有利用。下面把它加進來。

          #?面積
          >?areas?=?[64.4,?68,?74.1,?74.,?76.9,?78.1,?78.6]
          #?房齡
          >?ages?=?[31,?21,?19,?24,?17,?16,?17]
          >?X?=?np.stack([areas,?ages]).T
          >?print(X)
          array([[64.4,?31.?],
          ???????[68.?,?21.?],
          ???????[74.1,?19.?],
          ???????[74.?,?24.?],
          ???????[76.9,?17.?],
          ???????[78.1,?16.?],
          ???????[78.6,?17.?]])

          第1列是面積,第2列是房齡,每行數(shù)據(jù)代表一個樣本。

          下面我們改寫上面的線性回歸代碼,再次訓練一個線性回歸模型:

          model?=?Linear(2,?1)?#?in_features:?2??out_features:?1

          optimizer?=?SGD(model.parameters(),?lr=1e-4)

          loss?=?MSELoss()

          #?面積
          areas?=?[64.4,?68,?74.1,?74.,?76.9,?78.1,?78.6]
          #?房齡
          ages?=?[31,?21,?19,?24,?17,?16,?17]

          X?=?np.stack([areas,?ages]).T
          #?掛牌售價
          prices?=?[6.1,?6.25,?7.8,?6.66,?7.82,?7.14,?8.02]


          X?=?Tensor(X)
          y?=?Tensor(prices).reshape((-1,?1))

          epochs?=?1000
          losses?=?[]
          for?epoch?in?range(epochs):
          ??l?=?loss(model(X),?y)
          ??optimizer.zero_grad()
          ??l.backward()
          ??optimizer.step()
          ??epoch_loss?=?l.data

          ??losses.append(epoch_loss)
          ??if?(epoch+1)?%?20?==?0:
          ????print(f'epoch?{epoch?+?1},?loss?{float(epoch_loss):f}')

          輸出:

          epoch?20,?loss?10.742877
          epoch?40,?loss?8.136241
          epoch?60,?loss?6.171517
          epoch?80,?loss?4.690628
          epoch?100,?loss?3.574423
          epoch?120,?loss?2.733095
          epoch?140,?loss?2.098954
          epoch?160,?loss?1.620976
          epoch?180,?loss?1.260706
          epoch?200,?loss?0.989156
          epoch?220,?loss?0.784478
          epoch?240,?loss?0.630204
          epoch?260,?loss?0.513921
          epoch?280,?loss?0.426275
          ...
          epoch?1000,?loss?0.158022

          加上房齡信息,最終可以使損失下降到。我們來看一下此時的權重和偏置:

          >?w,?b?=?model.weight.data,model.bias.data.item()
          >?print(f'w:?{w},?b:{b}')
          w:?[[?0.10354146?-0.02362296]],?b:-0.00232952055510911

          可以看到,房齡特征對應的權重為,所以說房齡越大,房子的價值就越小,這一關系還是學到了的。

          我們的訓練集才7個樣本,這真的是太少了,如果你收集更多的數(shù)據(jù),一定可以獲得更好的效果。

          總結

          本文我們通過metagrad實現(xiàn)了線性回歸,以及一些基類方法。下篇文章我們就來學習邏輯回歸。

          最后一句:BUG,走你!

          Markdown筆記神器Typora配置Gitee圖床
          不會真有人覺得聊天機器人難吧(一)
          Spring Cloud學習筆記(一)
          沒有人比我更懂Spring Boot(一)
          入門人工智能必備的線性代數(shù)基礎

          1.看到這里了就點個在看支持下吧,你的在看是我創(chuàng)作的動力。
          2.關注公眾號,每天為您分享原創(chuàng)或精選文章
          3.特殊階段,帶好口罩,做好個人防護。

          瀏覽 24
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产麻豆 | 91亚洲性爱 | 国产精品激情综合 | 亚洲人成77777 | 三级片亚洲无码 |