第一次简单实现神经网络

好久不见!
推荐知乎上的三篇回答:
关于反向传播

搞了一下午终于搞懂了神经网络的基本基本基本原理。上面说的 45 分钟搞懂真的是太搞了。于是临摹了某位大神的代码(一模一样)并做了些解释。这个两层的网络主要任务是根据读入的身高体重来判断男女。

我们都知道,神经网络的每个节点的输出是前一层的每个节点的输出的加权和,加上某个偏置,再经过激活函数得到的。经过激活函数的目的是使运算变得不再线性,否则无论多少层的神经网络都可以简化为一层。这个函数有很多种,这里用 sigmoid 函数,并且在后面还需要用到它的导数:

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def deriv_sigmoid(x):
    y = sigmoid(x)
    return y * (1 - y)

我们还知道,神经网络分为训练和使用部分。而训练则可以看做不断使用+调整参数(权重和偏置)的过程。

神经网络的使用相对简单,将每一层的点值看做一个向量的话,层于层之间的转移就可以利用矩阵乘法实现。但初学 python 还不清楚矩阵和向量的写法,就手动展开了。为了方便,我们写成一个类。这个类包含 __init__ feedforward train 三个函数,后面会一一提到。

class NeuralNetwork:
    '''
    the network includes:
    - 2 inputs
    - 1 hidden layer with 2 neurons (h1, h2)
    - 1 output layer with 1 neurons (o1)
    '''
    def __init__(self):
        # later maybe it will be rewrite by the use of vector
        self.w1 = np.random.normal()    
        self.w2 = np.random.normal()
        self.w3 = np.random.normal()
        self.w4 = np.random.normal()
        self.w5 = np.random.normal()
        self.w6 = np.random.normal()
        
        self.b1 = np.random.normal()
        self.b2 = np.random.normal()
        self.b3 = np.random.normal()
        
    def feedforward(self, x):
        h1 = sigmoid(self.w1 * x[0] + self.w2 * x[1] + self.b1)
        h2 = sigmoid(self.w3 * x[0] + self.w4 * x[1] + self.b2)
        o1 = sigmoid(self.w5 * h1 + self.w6 * h2 + self.b3)
        return o1

这里要注意,这个代码中输出层仅有一个节点,而大多数神经网络中往往有多个输出节点。为了获得某个点成为答案的概率,我们需要对输出正规化。第 k 个点成为答案的概率为:
p k = e o k ∑ i e o i p_k=\frac{e^{o_k}}{\sum_i e^{o_i}} pk=ieoieok
这个式子的来源和合理性我并不清楚…

如果是使用的话,根据返回的 pi 最大的点就可以得出结果了。如果是训练,我们还要根据这个结果对网络进行修正。设我们得出的 p 为 p_pred,正确的概率为 p_true(p_pred,p_true 都是向量),对于某个测试集,定义平均方差 MSE 为:
1 n ∑ ( p p r e d i − p t r u e i ) 2 \frac 1n \sum(p_{pred_i}-p _{true_i})^2 n1(pprediptruei)2
为了使我们的网络更准确,我们希望最小化这个式子,方法是调整权重 w 和偏置 b,因为只有 w 和 b 使我们设定的。

事实上,MSE 函数可以看做是一个多元函数 F ( w 1 , w 2 , . . . , b 1 , b 2 , . . . ) F(w_1,w_2,...,b_1,b_2,...) F(w1,w2,...,b1,b2,...),为了得知每个元的改变对整体的影响情况,可以分别对每个元求偏导。具体的链式求导过程在上面反向传播的链接里讲得很清楚,就不多赘述了。根据求导的结果对每个参数进行修改,这样迭代多次,就完成了对神经网络的训练。这个过程成为反向传播,我认为是一个神经网络的灵魂。因为没有用矩阵,代码十分繁琐。


    def train(self, data, all_y_trues):
        learn_rate = 0.3
        epochs = 1000 # number of iteration

        for epoch in range(epochs):
            for x, y_true in zip(data, all_y_trues):
                sum_h1 = self.w1 * x[0] + self.w2 * x[1] + self.b1
                h1 = sigmoid(sum_h1)

                sum_h2 = self.w3 * x[0] + self.w4 * x[1] + self.b2
                h2 = sigmoid(sum_h2)

                sum_o1 = self.w5 * h1 + self.w6 * h2 + self.b3
                o1 = sigmoid(sum_o1)
                y_pred = o1

                dl_dypred = -2 * (y_true - y_pred)

                # o1
                # dy_dx means dy/dx
                dypred_dw5 = h1 * deriv_sigmoid(sum_o1)
                dypred_dw6 = h2 * deriv_sigmoid(sum_o1)
                dypred_db3 = deriv_sigmoid(sum_o1)

                dypred_dh1 = self.w5 * deriv_sigmoid(sum_o1)
                dypred_dh2 = self.w6 * deriv_sigmoid(sum_o1)

                # h1
                dh1_dw1 = x[0] * deriv_sigmoid(sum_h1)
                dh1_dw2 = x[1] * deriv_sigmoid(sum_h1)
                dh1_db1 = deriv_sigmoid(sum_h1)

                # h2
                dh2_dw3 = x[0] * deriv_sigmoid(sum_h2)
                dh2_dw4 = x[1] * deriv_sigmoid(sum_h2)
                dh2_db2 = deriv_sigmoid(sum_h2)

                # update
                # h1
                self.w1 -= learn_rate * dl_dypred * dypred_dh1 * dh1_dw1
                self.w2 -= learn_rate * dl_dypred * dypred_dh1 * dh1_dw2
                self.b1 -= learn_rate * dl_dypred * dypred_dh1 * dh1_db1

                # h2
                self.w3 -= learn_rate * dl_dypred * dypred_dh2 * dh2_dw3
                self.w4 -= learn_rate * dl_dypred * dypred_dh2 * dh2_dw4
                self.b2 -= learn_rate * dl_dypred * dypred_dh2 * dh2_db2

                # o1
                self.w5 -= learn_rate * dl_dypred * dypred_dw5
                self.w6 -= learn_rate * dl_dypred * dypred_dw6
                self.b3 -= learn_rate * dl_dypred * dypred_db3

            if epoch % 10 == 0:	# to see the process of training
                y_preds = np.apply_along_axis(self.feedforward, 1, data)
                loss = mse_loss(all_y_trues, y_preds)
                print("Epoch %d loss: %.3f" % (epoch, loss))

这里也有两个需要注意的地方。
一是代码中的learn_rate,指的是学习速率。如果不加以限制,对参数的改变很可能“过火”,导致直接越过更优的取值。
二是这个代码没有加入正则化的过程。正则化的存在是为了防止网络过度拟合。因为用来训练的数据集大小是有限的,如果不加入正则化很有可能导致训练出来的网络只对这个单一训练集拟合得很好,但对于普通的数据拟合效果不佳。然而具体如何正则化我还没有搞懂。

到这里,一个最简单的神经网络类就构建完成了。接下来的事情就非常轻松了。

完整代码:

import numpy as np

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def deriv_sigmoid(x):
    y = sigmoid(x)
    return y * (1 - y)

def mse_loss(y_true, y_pred):
    return ((y_true - y_pred)**2).mean()

class NeuralNetwork:
    '''
    the network includes:
    - 2 inputs
    - 1 hidden layer with 2 neurons (h1, h2)
    - 1 output layer with 1 neurons (o1)
    '''
    def __init__(self):
        # later maybe we can use vector to rewrite
        self.w1 = np.random.normal()    
        self.w2 = np.random.normal()
        self.w3 = np.random.normal()
        self.w4 = np.random.normal()
        self.w5 = np.random.normal()
        self.w6 = np.random.normal()
        
        self.b1 = np.random.normal()
        self.b2 = np.random.normal()
        self.b3 = np.random.normal()
        

    def feedforward(self, x):
        h1 = sigmoid(self.w1 * x[0] + self.w2 * x[1] + self.b1)
        h2 = sigmoid(self.w3 * x[0] + self.w4 * x[1] + self.b2)
        o1 = sigmoid(self.w5 * h1 + self.w6 * h2 + self.b3)
        return o1

    def train(self, data, all_y_trues):
        learn_rate = 0.3
        epochs = 1000 # number of iteration

        for epoch in range(epochs):
            for x, y_true in zip(data, all_y_trues):
                sum_h1 = self.w1 * x[0] + self.w2 * x[1] + self.b1
                h1 = sigmoid(sum_h1)

                sum_h2 = self.w3 * x[0] + self.w4 * x[1] + self.b2
                h2 = sigmoid(sum_h2)

                sum_o1 = self.w5 * h1 + self.w6 * h2 + self.b3
                o1 = sigmoid(sum_o1)
                y_pred = o1

                dl_dypred = -2 * (y_true - y_pred)

                # o1
                # dy_dx means dy/dx
                dypred_dw5 = h1 * deriv_sigmoid(sum_o1)
                dypred_dw6 = h2 * deriv_sigmoid(sum_o1)
                dypred_db3 = deriv_sigmoid(sum_o1)

                dypred_dh1 = self.w5 * deriv_sigmoid(sum_o1)
                dypred_dh2 = self.w6 * deriv_sigmoid(sum_o1)

                # h1
                dh1_dw1 = x[0] * deriv_sigmoid(sum_h1)
                dh1_dw2 = x[1] * deriv_sigmoid(sum_h1)
                dh1_db1 = deriv_sigmoid(sum_h1)

                # h2
                dh2_dw3 = x[0] * deriv_sigmoid(sum_h2)
                dh2_dw4 = x[1] * deriv_sigmoid(sum_h2)
                dh2_db2 = deriv_sigmoid(sum_h2)

                # update
                # h1
                self.w1 -= learn_rate * dl_dypred * dypred_dh1 * dh1_dw1
                self.w2 -= learn_rate * dl_dypred * dypred_dh1 * dh1_dw2
                self.b1 -= learn_rate * dl_dypred * dypred_dh1 * dh1_db1

                # h2
                self.w3 -= learn_rate * dl_dypred * dypred_dh2 * dh2_dw3
                self.w4 -= learn_rate * dl_dypred * dypred_dh2 * dh2_dw4
                self.b2 -= learn_rate * dl_dypred * dypred_dh2 * dh2_db2

                # o1
                self.w5 -= learn_rate * dl_dypred * dypred_dw5
                self.w6 -= learn_rate * dl_dypred * dypred_dw6
                self.b3 -= learn_rate * dl_dypred * dypred_db3

            if epoch % 10 == 0:	# to see the process of training
                y_preds = np.apply_along_axis(self.feedforward, 1, data)
                loss = mse_loss(all_y_trues, y_preds)
                print("Epoch %d loss: %.3f" % (epoch, loss))


data = np.array([
    [-2, -1],
    [25, 6],
    [17, 4],
    [-15, -6],
])
all_y_trues = np.array([
    1,
    0,
    0,
    1,
])  

network = NeuralNetwork()
network.train(data, all_y_trues)

kang = np.array([15, 5])    # myself
tmp = network.feedforward(kang)
gender = 'Male'
if tmp > 0.5: 
    gender = 'Female'
print('Kang:',gender) 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 首先,我们需要导入所需的Python库:import numpy as np import matplotlib.pyplot as plt from keras.models import Sequential from keras.layers import Dense# 设置随机种子 np.random.seed(7)# 导入数据集 dataset = np.loadtxt("pima-indians-diabetes.csv", delimiter=",")# 分割输入变量和输出变量 X = dataset[:,0:8] Y = dataset[:,8]# 创建模型 model = Sequential() model.add(Dense(12, input_dim=8, activation='relu')) model.add(Dense(8, activation='relu')) model.add(Dense(1, activation='sigmoid'))# 编译模型 model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])# 训练模型 model.fit(X, Y, epochs=150, batch_size=10)# 评估模型 scores = model.evaluate(X, Y) print("\n%s: %.2f%%" % (model.metrics_names[1], scores[1]*100)) ### 回答2: 建立一个简单神经网络代码可以使用一种非常流行的深度学习库,如TensorFlow或PyTorch。在这里,我将使用TensorFlow来说明。首先,我们需要导入所需的库和数据集。 ```python import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers # 导入数据集 (x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data() # 数据预处理 x_train = x_train.reshape(-1, 28*28).astype("float32") / 255.0 x_test = x_test.reshape(-1, 28*28).astype("float32") / 255.0 ``` 接下来,我们可以构建一个简单神经网络模型,例如,一个具有两个隐藏层的全连接网络。 ```python # 构建模型 model = keras.Sequential([ # 第一隐藏层 layers.Dense(64, activation="relu"), # 第二隐藏层 layers.Dense(64, activation="relu"), # 输出层 layers.Dense(10), ]) # 编译模型 model.compile( optimizer=keras.optimizers.Adam(), loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=["accuracy"], ) ``` 然后,我们可以使用训练集进行模型训练。 ```python # 训练模型 model.fit(x_train, y_train, batch_size=32, epochs=5, verbose=2) ``` 最后,我们可以使用测试集评估模型的性能。 ```python # 评估模型 model.evaluate(x_test, y_test, batch_size=32, verbose=2) ``` 这只是一个简单神经网络代码示例,用于识别手写数字数据集MNIST。根据不同的问题和数据集,你可能需要根据实际情况对网络进行适当的调整。 ### 回答3: 构建一个简单神经网络代码可以使用Python编程语言和一些流行的深度学习库,如TensorFlow或PyTorch。 以下是一个使用TensorFlow库构建简单神经网络的示例代码: ```python import tensorflow as tf import numpy as np # 构建训练数据 x_train = np.array([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=np.float32) y_train = np.array([[0], [1], [1], [0]], dtype=np.float32) # 定义神经网络模型 model = tf.keras.Sequential([ tf.keras.layers.Dense(2, activation='sigmoid'), # 隐藏层 tf.keras.layers.Dense(1, activation='sigmoid') # 输出层 ]) # 编译模型 model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) # 训练模型 model.fit(x_train, y_train, epochs=5000) # 用训练好的模型进行预测 x_test = np.array([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=np.float32) predictions = model.predict(x_test) print(predictions) ``` 这个代码实现了一个具有两个输入、一个隐藏层和一个输出层的简单神经网络。隐藏层和输出层都使用Sigmoid激活函数,模型使用Adam优化器进行训练,并使用二元交叉熵作为损失函数。 训练数据定义了4个逻辑门的输入和相应的输出,即异或门。通过反复迭代训练模型5000次,模型将学习到逼近异或门的函数。最后,使用训练好的模型对新的输入进行预测,并输出其预测结果。 注意,以上代码只是一个简单的示例,实际上,深度学习中的神经网络可以非常复杂,并且通常需要大量的数据和较长的训练时间才能得到质量较高的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值