<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>

          【深度學(xué)習(xí)】深度學(xué)習(xí)手寫代碼匯總(建議收藏,面試用)

          共 44529字,需瀏覽 90分鐘

           ·

          2021-09-02 23:12

          這幾天一些同學(xué)在面試的時候,遇到了一些手寫代碼的題,因為之前都沒有準(zhǔn)備到,所以基本上在寫的時候都有點蒙。

          今天我就把一些常見的考題給大家整理下,這些題也是我之前準(zhǔn)備面試的時候整理的,很多的代碼都是網(wǎng)上現(xiàn)有的代碼,感謝各位大佬的付出,我這里就作為一個搬運工了,把這些代碼跟我之前整理到的一些資料都給大家系統(tǒng)整理下,希望各位也可以去他們那里給個star或者贊!



          首先,在這里感謝大佬們的代碼倉庫:
          1.  https://github.com/heyxhh/nnet-numpy

          2. https://gitee.com/bitosky/numpy_cnn

          3. https://blog.csdn.net/csuyzt/article/details/82633051

          4. https://github.com/yizt/numpy_neural_network


          上面的大佬們,主要是使用numpy來搭建了一個神經(jīng)網(wǎng)絡(luò),我之前也是參考這些大佬們的代碼準(zhǔn)備的面試。這里給大家安利下他們的代碼庫,當(dāng)然,需要配合下我之前的一些文章呀~


          當(dāng)然,還有我自己的百面計算機(jī)視覺的面經(jīng)倉庫:https://github.com/zonechen1994/CV_Interview,歡迎大佬star!

          全連接層的前向與反向

          首先看下全連接層的前向與反向,這里先看下之前的一篇文章。

          面試必問|手撕反向傳播


          import numpy as np

          # 定義線性層網(wǎng)絡(luò)
          class Linear():
              """
              線性全連接層
              """

              def __init__(self, dim_in, dim_out):
                  """
                  參數(shù):
                      dim_in: 輸入維度
                      dim_out: 輸出維度
                  """

                  # 初始化參數(shù)
                  scale = np.sqrt(dim_in / 2)
                  self.weight = np.random.standard_normal((dim_in, dim_out)) / scale
                  self.bias = np.random.standard_normal(dim_out) / scale
                  # self.weight = np.random.randn(dim_in, dim_out)
                  # self.bias = np.zeros(dim_out)
                  
                  self.params = [self.weight, self.bias]
                  
              def __call__(self, X):
                  """
                  參數(shù):
                      X:這一層的輸入,shape=(batch_size, dim_in)
                  return:
                      xw + b
                  """

                  self.X = X
                  return self.forward()
              
              def forward(self):
                  return np.dot(self.X, self.weight) + self.bias
              
              def backward(self, d_out):
                  """
                  參數(shù):
                      d_out:輸出的梯度, shape=(batch_size, dim_out)
                  return:
                      返回loss對輸入 X 的梯度(前一層(l-1)的激活值的梯度)
                  """

                  # 計算梯度
                  # 對input的梯度有batch維度,對參數(shù)的梯度對batch維度取平均
                  d_x = np.dot(d_out, self.weight.T)  # 輸入也即上一層激活值的梯度
                  d_w = np.dot(self.X.T, d_out)  # weight的梯度
                  d_b = np.mean(d_out, axis=0)  # bias的梯度
                  
                  return d_x, [d_w, d_b]

          Dropout前向與反向

          這里給大家分享下我之前的兩篇文章:

          我丟!算法崗必問!建議收藏!


          我再丟! 算法必問!


          class Dropout():
              """
              在訓(xùn)練時隨機(jī)將部分feature置為0
              """

              def __init__(self, p):
                  """
                  parameters:
                      p: 保留比例
                  """

                  self.p = p
              
              def __call__(self, X, mode):
                  """
                  mode: 是在訓(xùn)練階段還是測試階段. train 或者 test
                  """

                  return self.forward(X, mode)
              
              def forward(self, X, mode):
                  if mode == 'train':
                      self.mask = np.random.binomial(1, self.p, X.shape) / self.p
                      out =  self.mask * X
                  else:
                      out = X
                  
                  return out
              
              def backward(self, d_out):
                  """
                  d_out: loss對dropout輸出的梯度
                  """

                  return d_out * self.mask

          激活函數(shù)之ReLu/Sigmoid/Tanh

          這里給大家看下我之前關(guān)于激活函數(shù)的一些總結(jié):

          非零均值?激活函數(shù)也太硬核了!


          Softmax與Sigmoid你還不知道存在這些聯(lián)系?


          ReLu

          import numpy as np

          # 定義Relu層
          class Relu(object):
              def __init__(self):
                  self.X = None
              
              def __call__(self, X):
                  self.X = X
                  return self.forward(self.X)
              
              def forward(self, X):
                  return np.maximum(0, X)
              
              def backward(self, grad_output):
                  """
                  grad_output: loss對relu激活輸出的梯度
                  return: relu對輸入input_z的梯度
                  """

                  grad_relu = self.X > 0  # input_z大于0的提放梯度為1,其它為0
                  return grad_relu * grad_output  # numpy中*為點乘

          Tanh


          class Tanh():
              def __init__(self):
                  self.X = None
              
              def __call__(self, X):
                  self.X = X
                  return self.forward(self.X)
              
              def forward(self, X):
                  return np.tanh(X)
              
              def backward(self, grad_output):
                  grad_tanh = 1 - (np.tanh(self.X)) ** 2
                  return grad_output * grad_tanh

          Sigmoid


          class Sigmoid():
              def __init__(self):
                  self.X = None
              
              def __call__(self, X):
                  self.X = X
                  return self.forward(self.X)
              
              def forward(self, X):
                  return self._sigmoid(X)
              
              def backward(self, grad_output):
                  sigmoid_grad = self._sigmoid(self.X) * (1 - self._sigmoid(self.X))
                  return grad_output * sigmoid_grad
              
              def _sigmoid(self, X):
                  return 1.0 / (1 + np.exp(-X))

          卷積層前向與反向傳播

          卷積在這里,如果你之前用過caffe,你就知道我們卷積是im2col來做的。這里先給出大佬的兩段代碼/

          Im2Col

          class Img2colIndices():
              """
              卷積網(wǎng)絡(luò)的滑動計算實際上是將feature map轉(zhuǎn)換成為矩陣乘法的方式。
              卷積計算forward前需要將feature map轉(zhuǎn)換成為cols格式,每一次滑動的窗口作為cols的一列
              卷積計算backward時需要將cols態(tài)的梯度轉(zhuǎn)換成為與輸入map shape一致的格式
              該輔助類完成feature map --> cols 以及 cols --> feature map
              設(shè)計卷積、maxpool、average pool都有可能用到該類進(jìn)行轉(zhuǎn)換操作
              """

              def __init__(self, filter_size, padding, stride):
                  """
                  parameters:
                      filter_shape: 卷積核的尺寸(h_filter, w_filter)
                      padding: feature邊緣填充0的個數(shù)
                      stride: filter滑動步幅
                  """

                  self.h_filter, self.w_filter = filter_size
                  self.padding = padding
                  self.stride = stride
              
              def get_img2col_indices(self, h_out, w_out):
                  """
                  獲得需要由image轉(zhuǎn)換為col的索引, 返回的索引是在feature map填充后對于尺寸的索引
                  獲得每次卷積時,在feature map上卷積的元素的坐標(biāo)索引。以后img2col時根據(jù)索引獲得
                  i 的每一行,如第r行是filter第r個元素(左右上下的順序)在不同位置卷積時點乘的元素的位置的row坐標(biāo)索引
                  j 的每一行,如第r行是filter第r個元素(左右上下的順序)在不同位置卷積時點乘的元素的位置的column坐標(biāo)索引
                  結(jié)果i、j每一列,如第c列是filter第c次卷積的位置卷積的k×k個元素(左右上下的順序)。
                  每一列長filter_height*filter_width*C,由于C個通道,每C個都是重復(fù)的,表示在第幾個通道上做的卷積。
                  parameters:
                      h_out: 卷積層輸出feature的height
                      w_out: 卷積層輸出feature的width。每次調(diào)用imgcol時計算得到
                  return:
                      k: shape=(filter_height*filter_width*C, 1), 每挨著的filter_height*filter_width元素值都一樣,表示從第幾個通道取點
                      i: shape=(filter_height*filter_width*C, out_height*out_width), 依次待取元素的橫坐標(biāo)索引
                      j: shape=(filter_height*filter_width*C, out_height*out_width), 依次待取元素的縱坐標(biāo)索引
                  """

                  i0 = np.repeat(np.arange(self.h_filter), self.w_filter)
                  i1 = np.repeat(np.arange(h_out), w_out) * self.stride
                  i = i0.reshape(-11) + i1
                  i = np.tile(i, [self.c_x, 1])
                  
                  j0 = np.tile(np.arange(self.w_filter), self.h_filter)
                  j1 = np.tile(np.arange(w_out), h_out) * self.stride
                  j = j0.reshape(-11) + j1
                  j = np.tile(j, [self.c_x, 1])
                  
                  k = np.repeat(np.arange(self.c_x), self.h_filter * self.w_filter).reshape(-11)
                  
                  return k, i, j
              
              def img2col(self, X):
                  """
                  基于索引取元素的方法實現(xiàn)img2col
                  parameters:
                      x: 輸入feature map,shape=(batch_size, channels, height, width)
                  return:
                      轉(zhuǎn)換img2col,shape=(h_filter * w_filter*chanels, batch_size * h_out * w_out)
                  """

                  self.n_x, self.c_x, self.h_x, self.w_x = X.shape

                  # 首先計算出輸出特征的尺寸
                  # 計算輸出feature的尺寸,并且保證是整數(shù)
                  h_out = (self.h_x + 2 * self.padding - self.h_filter) / self.stride + 1
                  w_out = (self.w_x + 2 * self.padding - self.w_filter) / self.stride + 1
                  if not h_out.is_integer() or not w_out.is_integer():
                      raise Exception("Invalid dimention")
                  else:
                      h_out, w_out = int(h_out), int(w_out)  # 上一步在進(jìn)行除法后類型會是float
                  
                  # 0填充輸入feature map
                  x_padded = None
                  if self.padding > 0:
                      x_padded = np.pad(X, ((00), (00), (self.padding, self.padding), (self.padding, self.padding)), mode='constant')
                  else:
                      x_padded = X
                  
                  # 在計算出輸出feature尺寸后,并且0填充X后,獲得img2col_indices
                  # img2col_indices設(shè)為實例的屬性,col2img時用,避免重復(fù)計算
                  self.img2col_indices = self.get_img2col_indices(h_out, w_out)
                  k, i, j = self.img2col_indices
                  
                  # 獲得參與卷積計算的col形式
                  cols = x_padded[:, k, i, j]  # shape=(batch_size, h_filter*w_filter*n_channel, h_out*w_out)
                  cols = cols.transpose(120).reshape(self.h_filter * self.w_filter * self.c_x, -1)  # reshape
                  
                  return cols
              
              def col2img(self, cols):
                  """
                  img2col的逆過程
                  卷積網(wǎng)絡(luò),在求出x的梯度時,dx是col矩陣的形式(filter_height*filter_width*chanels, batch_size*out_height*out_width)
                  將dx有col格式轉(zhuǎn)換成feature map的原尺寸格式。由get_img2col_indices獲得該尺寸下的索引,使用numpt.add.at方法還原成img格式
                  parameters:
                      cols: dx的col形式, shape=(h_filter*w_filter*n_chanels, batch_size*h_out*w_out)
                  """

                  # 將col還原成img2col的輸出shape
                  cols = cols.reshape(self.h_filter * self.w_filter * self.c_x, -1, self.n_x)
                  cols = cols.transpose(201)
                  
                  h_padded, w_padded = self.h_x + 2 * self.padding, self.w_x + 2 * self.padding
                  x_padded = np.zeros((self.n_x, self.c_x, h_padded, w_padded))
                  
                  k, i, j = self.img2col_indices
                  
                  np.add.at(x_padded, (slice(None), k, i, j), cols)
                  
                  if self.padding == 0:
                      return x_padded
                  else:
                      return x_padded[:, :, self.padding : -self.padding, self.padding : -self.padding]

          Conv2d前向與反向

          卷積的過程,會調(diào)用im2col的函數(shù)。

          class Conv2d():
              def __init__(self, in_channels, n_filter, filter_size, padding, stride):
                  """
                  parameters:
                      in_channel: 輸入feature的通道數(shù)
                      n_filter: 卷積核數(shù)目
                      filter_size: 卷積核的尺寸(h_filter, w_filter)
                      padding: 0填充數(shù)目
                      stride: 卷積核滑動步幅
                  """

                  self.in_channels = in_channels
                  self.n_filter = n_filter
                  self.h_filter, self.w_filter = filter_size
                  self.padding = padding
                  self.stride = stride
                  
                  # 初始化參數(shù),卷積網(wǎng)絡(luò)的參數(shù)size與輸入的size無關(guān)
                  self.W = np.random.randn(n_filter, self.in_channels, self.h_filter, self.w_filter) / np.sqrt(n_filter / 2.)
                  self.b = np.zeros((n_filter, 1))
                  
                  self.params = [self.W, self.b]
                  
              def __call__(self, X):
                  # 計算輸出feature的尺寸
                  self.n_x, _, self.h_x, self.w_x = X.shape
                  self.h_out = (self.h_x + 2 * self.padding - self.h_filter) / self.stride + 1
                  self.w_out = (self.w_x + 2 * self.padding - self.w_filter) / self.stride + 1
                  if not self.h_out.is_integer() or not self.w_out.is_integer():
                      raise Exception("Invalid dimensions!")
                  self.h_out, self.w_out = int(self.h_out), int(self.w_out)
                  
                  # 聲明Img2colIndices實例
                  self.img2col_indices = Img2colIndices((self.h_filter, self.w_filter), self.padding, self.stride)
                  
                  return self.forward(X)
              
              def forward(self, X):
                  # 將X轉(zhuǎn)換成col
                  self.x_col = self.img2col_indices.img2col(X)
                  
                  # 轉(zhuǎn)換參數(shù)W的形狀,使它適合與col形態(tài)的x做計算
                  self.w_row = self.W.reshape(self.n_filter, -1)
                  
                  # 計算前向傳播
                  out = self.w_row @ self.x_col + self.b  # @在numpy中相當(dāng)于矩陣乘法,等價于numpy.matmul()
                  out = out.reshape(self.n_filter, self.h_out, self.w_out, self.n_x)
                  out = out.transpose(3012)
                  
                  return out
              
              def backward(self, d_out):
                  """
                  parameters:
                      d_out: loss對卷積輸出的梯度
                  """

                  # 轉(zhuǎn)換d_out的形狀
                  d_out_col = d_out.transpose(1230)
                  d_out_col = d_out_col.reshape(self.n_filter, -1)
                  
                  d_w = d_out_col @ self.x_col.T
                  d_w = d_w.reshape(self.W.shape)  # shape=(n_filter, d_x, h_filter, w_filter)
                  d_b = d_out_col.sum(axis=1).reshape(self.n_filter, 1)
                  
                  d_x = self.w_row.T @ d_out_col
                  # 將col態(tài)的d_x轉(zhuǎn)換成image格式
                  d_x = self.img2col_indices.col2img(d_x)
                  
                  return d_x, [d_w, d_b]

          MaxPool2d


          class Maxpool():
              def __init__(self, size, stride):
                  """
                  parameters:
                      size: maxpool框框的尺寸,int類型
                      stride: maxpool框框的滑動步幅,一般設(shè)計步幅和size一樣
                  """

                  self.size = size  # maxpool框的尺寸
                  self.stride = stride
                  
              def __call__(self, X):
                  """
                  parameters:
                      X: 輸入feature,shape=(batch_size, channels, height, width)
                  """

                  self.n_x, self.c_x, self.h_x, self.w_x = X.shape
                  # 計算maxpool輸出尺寸
                  self.h_out = (self.h_x - self.size) / self.stride + 1
                  self.w_out = (self.w_x - self.size) / self.stride + 1
                  if not self.h_out.is_integer() or not self.w_out.is_integer():
                      raise Exception("Invalid dimensions!")
                  self.h_out, self.w_out = int(self.h_out), int(self.w_out)
                  
                  # 聲明Img2colIndices實例
                  self.img2col_indices = Img2colIndices((self.size, self.size), padding=0, stride=self.stride) # maxpool不需要padding
                  
                  return self.forward(X)
              
              def forward(self, X):
                  """
                  parameters:
                      X: 輸入feature,shape=(batch_size, channels, height, width)
                  """

                  x_reshaped = X.reshape(self.n_x * self.c_x, 1, self.h_x, self.w_x)
                  self.x_col = self.img2col_indices.img2col(x_reshaped)
                  self.max_indices = np.argmax(self.x_col, axis=0)
                  
                  out = self.x_col[self.max_indices, range(self.max_indices.size)]
                  out = out.reshape(self.h_out, self.w_out, self.n_x, self.c_x).transpose(2301)
                  return out
              
              def backward(self, d_out):
                  """
                  parameters:
                      d_out: loss多maxpool輸出的梯度,shape=(batch_size, channels, h_out, w_out)
                  """

                  d_x_col = np.zeros_like(self.x_col)  # shape=(size*size, h_out*h_out*batch*C)
                  d_out_flat = d_out.transpose(2301).ravel()
                  
                  d_x_col[self.max_indices, range(self.max_indices.size)] = d_out_flat
                  # 將d_x由col形態(tài)轉(zhuǎn)換到img形態(tài)
                  d_x = self.img2col_indices.col2img(d_x_col)
                  d_x = d_x.reshape(self.n_x, self.c_x, self.h_x, self.w_x)
                  
                  return d_x

          當(dāng)然,如果不用Im2col的話,就更好理解了。在平均池化的時候,就不需要進(jìn)行標(biāo)記位置,可以直接用均值代替某一個區(qū)域就好了。


          BatchNorm2d前向反向

          這里就要安利下這篇文章了~

          最全Normalization!建議收藏,面試必問!


          class BatchNorm2d():
              """
              對卷積層來說,批量歸一化發(fā)生在卷積計算之后、應(yīng)用激活函數(shù)之前。
              如果卷積計算輸出多個通道,我們需要對這些通道的輸出分別做批量歸一化,且每個通道都擁有獨立的拉伸和偏移參數(shù),并均為標(biāo)量。
              設(shè)小批量中有 m 個樣本。在單個通道上,假設(shè)卷積計算輸出的高和寬分別為 p 和 q 。我們需要對該通道中 m×p×q 個元素同時做批量歸一化。
              對這些元素做標(biāo)準(zhǔn)化計算時,我們使用相同的均值和方差,即該通道中 m×p×q 個元素的均值和方差。
              
              將訓(xùn)練好的模型用于預(yù)測時,我們希望模型對于任意輸入都有確定的輸出。
              因此,單個樣本的輸出不應(yīng)取決于批量歸一化所需要的隨機(jī)小批量中的均值和方差。
              一種常用的方法是通過移動平均估算整個訓(xùn)練數(shù)據(jù)集的樣本均值和方差,并在預(yù)測時使用它們得到確定的輸出。
              """

              def __init__(self, n_channel, momentum):
                  """
                  parameters:
                      n_channel: 輸入feature的通道數(shù)
                      momentum: moving_mean/moving_var迭代調(diào)整系數(shù)
                  """

                  self.n_channel = n_channel
                  self.momentum = momentum
                  
                  # 參與求梯度和迭代的拉伸和偏移參數(shù),分別初始化成1和0
                  self.gamma = np.ones((1, n_channel, 11))
                  self.beta = np.zeros((1, n_channel, 11))
                  
                  # 測試時使用的參數(shù),初始化為0,需在訓(xùn)練時動態(tài)調(diào)整
                  self.moving_mean = np.zeros((1, n_channel, 11))
                  self.moving_var = np.zeros((1, n_channel, 11))
                  
                  self.params = [self.gamma, self.beta]
              
              def __call__(self, X, mode):
                  """
                  X: shape = (N, C, H, W)
                  mode: 訓(xùn)練階段還是測試階段,train或test, 需要在調(diào)用時傳參
                  """

                  self.X = X  # 求gamma的梯度時用
                  return self.forward(X, mode)
              
              def forward(self, X, mode):
                  """
                  X: shape = (N, C, H, W)
                  mode: 訓(xùn)練階段還是測試階段,train或test, 需要在調(diào)用時傳參
                  """

                  if mode != 'train':
                      # 如果是在預(yù)測模式下,直接使用傳入的移動平均所得的均值和方差
                      self.x_norm = (X - self.moving_mean) / np.sqrt(self.moving_var + 1e-5)
                  else:
                      # 使用二維卷積層的情況,計算通道維上(axis=1)的均值和方差。
                      # 這里我們需要保持X的形狀以便后面可以做廣播運算
                      mean = X.mean(axis=(023), keepdims=True)
                      self.var = X.var(axis=(023), keepdims=True)  # 設(shè)為self,是因為backward時會用到
                      
                      # 訓(xùn)練模式下用當(dāng)前的均值和方差做標(biāo)準(zhǔn)化。設(shè)為類實例的屬性,backward時用
                      self.x_norm = (X - mean) / (np.sqrt(self.var + 1e-5))
                      
                      # 更新移動平均的均值和方差
                      self.moving_mean = self.momentum * self.moving_mean + (1 - self.momentum) * mean
                      self.moving_var = self.momentum * self.moving_var + (1 - self.momentum) * self.var
                  # 拉伸和偏移
                  out = self.x_norm * self.gamma + self.beta
                  return out
              
              def backward(self, d_out):
                  """
                  d_out的形狀與輸入的形狀一樣
                  """

                  d_gamma = (d_out * self.x_norm).sum(axis=(023), keepdims=True)
                  d_beta = d_out.sum(axis=(023), keepdims=True)
                  
                  d_x = (d_out * self.gamma) / np.sqrt(self.var + 1e-5)
                  
                  return d_x, [d_gamma, d_beta]

          Flatten層

          這個層的作用,主要是進(jìn)行tensor拉直的操作,方便進(jìn)行全連接的進(jìn)行。

          class Flatten():
              """
              最后的卷積層輸出的feature若要連接全連接層需要將feature拉平
              單獨建立一個模塊是為了方便梯度反向傳播
              """

              def __init__(self):
                  pass
              
              def __call__(self, X):
                  self.x_shape = X.shape # (batch_size, channels, height, width)
                  
                  return self.forward(X)
              
              def forward(self, X):
                  out = X.ravel().reshape(self.x_shape[0], -1)
                  return out
              
              def backward(self, d_out):
                  d_x = d_out.reshape(self.x_shape)
                  return d_x

          損失函數(shù)

          這里以交叉熵?fù)p失函數(shù)為例:

          import numpy as np

          # 交叉熵?fù)p失
          class CrossEntropyLoss():
              """
              對最后一層的神經(jīng)元輸出計算交叉熵?fù)p失
              """

              def __init__(self):
                  self.X = None
                  self.labels = None
              
              def __call__(self, X, labels):
                  """
                  參數(shù):
                      X: 模型最后fc層輸出
                      labels: one hot標(biāo)注,shape=(batch_size, num_class)
                  """

                  self.X = X
                  self.labels = labels

                  return self.forward(self.X)
              
              def forward(self, X):
                  """
                  計算交叉熵?fù)p失
                  參數(shù):
                      X:最后一層神經(jīng)元輸出,shape=(batch_size, C)
                      label:數(shù)據(jù)onr-hot標(biāo)注,shape=(batch_size, C)
                  return:
                      交叉熵loss
                  """

                  self.softmax_x = self.softmax(X)
                  log_softmax = self.log_softmax(self.softmax_x)
                  cross_entropy_loss = np.sum(-(self.labels * log_softmax), axis=1).mean()
                  return cross_entropy_loss
              
              def backward(self):
                  grad_x =  (self.softmax_x - self.labels)  # 返回的梯度需要除以batch_size
                  return grad_x / self.X.shape[0]
                  
              def log_softmax(self, softmax_x):
                  """
                  參數(shù):
                      softmax_x, 在經(jīng)過softmax處理過的X
                  return: 
                      log_softmax處理后的結(jié)果shape = (m, C)
                  """

                  return np.log(softmax_x + 1e-5)
              
              def softmax(self, X):
                  """
                  根據(jù)輸入,返回softmax
                  代碼利用softmax函數(shù)的性質(zhì): softmax(x) = softmax(x + c)
                  """

                  batch_size = X.shape[0]
                  # axis=1 表示在二維數(shù)組中沿著橫軸進(jìn)行取最大值的操作
                  max_value = X.max(axis=1)
                  #每一行減去自己本行最大的數(shù)字,防止取指數(shù)后出現(xiàn)inf,性質(zhì):softmax(x) = softmax(x + c)
                  # 一定要新定義變量,不要用-=,否則會改變輸入X。因為在調(diào)用計算損失時,多次用到了softmax,input不能改變
                  tmp = X - max_value.reshape(batch_size, 1)
                  # 對每個數(shù)取指數(shù)
                  exp_input = np.exp(tmp)  # shape=(m, n)
                  # 求出每一行的和
                  exp_sum = exp_input.sum(axis=1, keepdims=True)  # shape=(m, 1)
                  return exp_input / exp_sum

          優(yōu)化器

          一文搞定面試中的優(yōu)化算法


          SGD

          class SGD():
              """
              隨機(jī)梯度下降
              parameters: 模型需要訓(xùn)練的參數(shù)
              lr: float, 學(xué)習(xí)率
              momentum: float, 動量因子,默認(rèn)為None不使用動量梯度下降
              """

              def __init__(self, parameters, lr, momentum=None):
                  self.parameters = parameters
                  self.lr = lr
                  self.momentum = momentum

                  if momentum is not None:
                      self.velocity = self.velocity_initial()

              def update_parameters(self, grads):
                  """
                  grads: 調(diào)用network的backward方法,返回的grads.
                  """

                  if self.momentum == None:
                      for param, grad in zip(self.parameters, grads):
                          param -= self.lr * grad
                  else:
                      for i in range(len(self.parameters)):
                          self.velocity[i] = self.momentum * self.velocity[i] - self.lr * grads[i]
                          self.parameters[i] += self.velocity[i]
              
              def velocity_initial(self):
                  """
                  初始化velocity,按照parameters的參數(shù)順序依次將v初始化為0
                  """

                  velocity = []
                  for param in self.parameters:
                      velocity.append(np.zeros_like(param))
                  return velocity

          - END -

          作者簡介:復(fù)旦在讀博士,94年已婚有娃的前bt算法工程師。雙非材料本科出身,零基礎(chǔ)跨專業(yè)考研到985cs專業(yè)。


          往期精彩回顧




          本站qq群851320808,加入微信群請掃碼:
          瀏覽 61
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  AV软件在线免费观看 | 操逼精品视频 | 国产免费性爱视频 | 天天日天天干天天射 | 三级电影在线91 |