単純な完全に接続されたネットワークを最初から作成する(Pythonバージョン)-完全に接続されたニューラルネットワーク(1)

一緒に書く習慣をつけましょう!「ナゲッツデイリーニュープラン4月アップデートチャレンジ」に参加して7日目です。クリックしてイベントの詳細をご覧ください

モチベーション

すべてがやる気になります。つまり、それを行う理由を見つける必要があります。では、なぜニューラルネットワークの単純なPythonバージョンを最初から作成する必要があるのでしょうか。ネットワークを好きなように定義できる優れたニューラルネットワークフレームワークはたくさんあります。それなら、私の文章は彼らほど良くないはずです。すべてが絶対的ではありませんが、基本的に私がそれらを超えることは不可能です。ハハ、実際、比較はありません。しかし、なぜ私はまだ書きたいのですか、それは時間の無駄ではありませんか?実際、ディープラーニングを学ぶことは自分でネットワークを書くことが最善であるというAndrei Capasの提案のためであり、それが私がネットワークを書く動機ですゼロから。

デザインモデル

まず、モデルはパラメータのセットです。関数セットでは、ネットワーク構造が決定されます。つまり、この関数セットが決定されます。トレーニングを通じて、この関数セットから適切な関数を見つける必要があります。各関数はパラメーターに対応します。また、関数セット内の関数間の違いを区別するために使用されるのはこれらのパラメーターです。

前提

ニューラルネットワークを理解する必要がありますが、これはすべて理論的であり、関数型プログラミングを使用してニューラルネットワークを最初から実装する必要があります。

  • モデルの構築、順方向伝搬、逆方向伝搬、パラメーターの更新などの各ステップの説明を容易にするために、オブジェクト指向の考え方に基づいてコーディングするのではなく、機能的な方法でコーディングしました。
  • 共有では、ニューラルネットワークの実装で難しい点であるバックプロパゲーションのプロセスに焦点を当てます。
  • numpyを使用して最急降下法を実現し、パラメーターを最適化することで、誰もが最急降下法をより深く理解できるようになります

まず、モデルモデルはディクショナリの形式で保存され、パラメータはディクショナリの形式で保存されます。

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
复制代码

ここでは、配列を操作するためのライブラリであるnumpyと、視覚化作業を行うためのmatplotlibのみを使用しています。

モデルを初期化します

まず、ここで実装されているネットワークはまだ比較的基本的なものであり、単純な直列構造のネットワークであり、複雑な構造はありません。しかし、この一連の共有がそこで止まらないことも願っています。

def initialize_model(dimensions):
    '''
    输入 dimension 是一个定义网络各个层神经元个数的列表,返回是一个具有以下字段的字典结构的
    通过这个字典结果我们可以还原出一个网络大概结构或者说是形状
      model['nlayers'] : 神经网络的层数
      model['weights'] : 神经网络各层的权重(weight)矩阵的集合
      model['biases'] :  神经网络各层的偏置(bias)向量的集合
    '''
    weights, biases = [], []
    L = len(dimensions) - 1 # number of layers (i.e., excludes input layer)
    for l in range(L):
        W = np.random.randn(dimensions[l+1], dimensions[l])
        b = np.random.randn(dimensions[l+1], 1)
        weights.append(W)
        biases.append(b)
    return dict(weights=weights, biases=biases, nlayers=L)
复制代码

根据输入,我们可以看到输入是一个 784 维度向量,隐含层是 15 神经网元的全连接层,输出层 10 维向量。看到这里做过神经网络一定露出笑容,这不是 hello MNIST 吗,神经网络中的 hello world,784 是数字尺寸 28 x 28 大小图像展平的维度,输出 10 是 0 到 9 10 个数字的类别。

dimensions = [784, 15, 10]
model = initialize_model(dimensions)
for k, (W, b) in enumerate(zip(model['weights'], model['biases'])):
    print(f'Layer {k+1}:\tShape of W{k+1}: {W.shape}\tShape of b{k+1}: {b.shape}')
复制代码
Layer 1: Shape of W1: (15, 784) Shape of b1: (15, 1) 
Layer 2: Shape of W2: (10, 15) Shape of b2: (10, 1)
复制代码

其实这里只有 2 层全连接,其中第一层权重参数 W 15 ×× 784 W_{15 \times 784} 而输入是一个 784 维向量

Y 15 ×× 1 = W 15 ×× 784 バツ 784 ×× 1 + b 15 ×× 1 y_{15 \times 1} = W_{15 \times 784}x_{784 \times 1} + b_{15 \times 1}

而对于 2 层,也就是所谓输出层

我们可以同过下面代码来查看具体权重随机初始化的值

print(f'W2:\n\n{model["weights"][1]}')  
print(f'b2:\n\n{model["biases"][1]}')   
复制代码

实现激活函数、loss 函数以及其求导

激活函数

这里激活函数采用 sigmoid

σ (( バツ )。 = 1 1 + exp (( バツ )。 = exp (( バツ )。 1 + exp (( バツ )。 \sigma(x) = \frac{1}{1 + \exp(-x)} = \frac{\exp(x)}{1 + \exp(x)}
import math

def sigmoid(x):
  return 1 / (1 + math.exp(-x))
复制代码

sigmoid 函数求导

σ (( バツ )。 = σ (( バツ )。 (( 1 σ (( バツ )。 )。 \sigma^{\prime}(x) = \sigma(x)(1 - \sigma(x))

为了增加 sigmoid 函数对于较大整数或者较大负数的 robust 修改如下

σ (( バツ )。 = {{ 1 1 + exp ( x ) x 0 1 1 1 + exp ( x ) otherwise. \sigma(x) = \begin{cases} \frac{1}{1 + \exp(-x)} & x \ge 0\\ 1 -\frac{1}{1 + \exp(x)} & \text{otherwise.} \end{cases}
def sigma(x):
    '''这里输入是一个向量'''
    return np.where(x>=0, 1/(1+np.exp(-x)), 1 - 1/(1+np.exp(x))) 
def sigma_prime(x):
    return sigma(x)*(1-sigma(x)) # Derivative of logistic function
复制代码

おすすめ

転載: juejin.im/post/7083826043278229517