神经网络入门概述--知乎转载

1.基本模块搭建:
在这里插入图片描述

说明:这个基本的神经元模块中经历了三步运算:
先将两个输入乘以权重(weight)
x1 --> x1 * w1
x2 --> x2* w2
两个结果相加之后,再加上一个偏置(bias)
(x1 * w1 + x2 * w2) + b
最后经过激活函数(activation function)
y = f(x1 * w1 + x2 * w2 + b)
激活函数:将无限制的输入转换为可测试的输出。常用的有sigmoid函数:
在这里插入图片描述

上述过程以python程序表达为:

#模块导入
import numpy as np

#激活函数选取:此处选择sigmoid函数
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

#神经元类定义:
class Neuron:
    def __init__(self, weights, bias):
        self.weights = weights
        self.bias = bias
        
    def feedforward(self, inputs):
        #权重输入,加入权重
        total = np.dot(self.weights, inputs) + self.bias
        return sigmoid(total)

weights = np.array([0, 1]) #w1, w2 = 0, 1
bias = 4 #b = 4
n = Neuron(weights, bias)#类实例化
x = np.array([2, 3])#输入变量x1, x2
print(n.feedforward(x))  

神经网络搭建:
神经元输入向前传递到输出的过程称为前馈(feedforward)
在这里插入图片描述

假设上述神经网络中所有神经元的权重w = [0, 1]和偏置b = 0,激活函数为sigmoid函数。
那么最终输出的过程为:
第二层(隐藏层)的神经元:
h1= h2 = f(w * x + b) = f([0, 1]*[2, 3].T + 0) = f(3) = sigmoid(3) = 0.9526
第三层(输出层)的神经元:
o1 = f(w * h + b) = f([0, 1] * [h1, h2].T + 0) = f(0.9526) = sigmoid(0.9526) = 0.7216

以上python程序表达为:

#模块导入
import numpy as np

'''
A neural network with:
-2 inputs
-a hidden layer with 2 neurons(h1, h2)
-a output layer with 1 neurons(o1)
Each neuron has the same weights and bias:
-w = [0,1]
-b = 0
'''
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

class MyNeuralNetwork:
    def __init__(self, weights, bias):
        self.weights = weights
        self.bias = bias
        self.h1 = 0
        self.h2 = 0
        self.o1 = 0
        
    def feedforward(self, inputs):
        temp_hidden = np.dot(self.weights, inputs)
        self.h1 = sigmoid(temp_hidden + self.bias)
        self.h2 = self.h1
        temp_out = np.dot(self.weights, np.array([self.h1, self.h2]))
        self.o1 = sigmoid(temp_out + self.bias)
        return self.o1
    
x = np.array([2, 3])
weights = np.array([0, 1])
bias = 0
n = MyNeuralNetwork(weights, bias)

print(n.feedforward(x))

训练神经网络
例如:对于一个数据集,包含4个人的身高和体重和性别。
在这里插入图片描述

目前的目标在于训练一个神经网络,实现根据体重和身高来预测一个人的性别。
(1)数据处理:
对身高,体重固定的减去一个固定数值,把性别男定义为1,性别女定义为0。
此时训练集变化为:
在这里插入图片描述

(2)训练数据效果评价:
评价训练的神经网络的好坏,使用**损失(loss)来定义。
比如用
均方误差(MSE)**定义损失:
M S E = 1 n ∗ ∑ i = 1 4 ( y t r u e − y p r e d ) 2 MSE = \frac{1}{n}*\sum_{i =1}^{4}(y_{true} - y_{pred})^{2} MSE=n1i=14(ytrueypred)2
其中,n代表样本实例的数量,这个数据集中是4;y代表性别,ytrue代表真实的y值,ypred代表变量的预测值。
训练神经网络就是将损失最小化。
(3)均方误差例化:
如果预测输出一直为0,即y_pred = [0, 0, 0, 0]
那么最终的损失为:

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

y_true = np.array([1, 0, 0, 1])
y_pred = np.array([0, 0, 0, 0])
Mse_Loss(y_true, y_pred)

最终结果为:0.5。
(4)减少损失:
初始想法:改变权重和偏置可以影响预测值。
具体做法:由单个样本实例作为整个数据集,选择Alice一个人的数据,则损失函数为:
M S E = 1 1 ∗ ∑ i = 1 1 ( 1 − y p r e d ) 2 = ( 1 − y p r e d ) 2 MSE = \frac{1}{1}*\sum_{i =1}^{1}(1 - y_{pred})^{2} = (1 - y_{pred})^{2} MSE=11i=11(1ypred)2=(1ypred)2
而预测值由一系列的网络权重和偏置计算出来的:
在这里插入图片描述
由上图可知,损失函数与多个变量(w1, w2, w3, w4, w5, w6, b1, b2, b3)有关。
即为:
L(w1, ,w2, w3, w4, w5, w6, b1, b2, b3)
猜想:如果调整一下w1,看loss的大小变化?
实操:
( ∂ L ∂ w 1 ) = ( ∂ L ∂ y p r e d ) ∗ ( ∂ y p r e d ∂ w 1 ) − − ( 1 ) (\frac{\partial L}{\partial w_{1}}) = (\frac{\partial L}{\partial y_{pred}})*(\frac{\partial y_{pred}}{\partial w_{1}})--(1) (w1L)=(ypredL)(w1ypred)(1)
L = ( ( 1 − y p r e d ) 2 ) − − ( 2 ) L = ((1 - y_{pred})^{2})--(2) L=((1ypred)2)(2)
则:
∂ L ∂ y p r e d = − 2 ∗ ( 1 − y p r e d ) − − ( 3 ) \frac{\partial L}{\partial y_{pred}} = -2 * (1 - y_{pred}) --(3) ypredL=2(1ypred)(3)

此时我们获取y_pred和w1的关系,则由于:
y p r e d = o 1 = f ( w 5 ∗ h 1 + w 6 ∗ h 2 + b 3 ) − − ( 4 ) y_{pred} = o1 = f(w5 * h1 + w6 * h2 + b3) --(4) ypred=o1=f(w5h1+w6h2+b3)(4)
但是只有神经元h1和w1有关系,那么y_pred对w1的导数为:
∂ y p r e d ∂ h 1 = w 5 ∗ f ′ ( w 5 h 1 + w 6 h 2 + b 3 ) − − ( 5 ) \frac{\partial y_{pred}}{\partial h1} = w5 * f^{'}(w5h1 + w6h2 +b3)-- (5) h1ypred=w5f(w5h1+w6h2+b3)(5)
h 1 = f ( w 1 x 1 + w 2 x 2 + b 1 ) − − ( 6 ) h1 = f(w1x1 + w2x2 + b1)--(6) h1=f(w1x1+w2x2+b1)(6)
∂ h 1 ∂ w 1 = x 1 ∗ f ′ ( w 1 x 1 + w 2 x 2 + b 1 ) − − ( 7 ) \frac{\partial h1}{\partial w1} = x1 * f^{'}(w1x1 + w2x2 +b1) --(7) w1h1=x1f(w1x1+w2x2+b1)(7)
激活函数选为sigmoid函数,那么导数求解为:
s i g m o i d ( x ) = f ( x ) = 1 1 + e − x − − ( 8 ) sigmoid(x) = f(x) = \frac{1}{1 + e^{-x}}--(8) sigmoid(x)=f(x)=1+ex1(8)
f ′ ( x ) = e x ( 1 + e − x ) 2 = f ( x ) ∗ ( 1 − f ( x ) ) − − ( 9 ) f^{'}(x) = \frac{e^{x}}{(1 + e^{-x})^{2}} = f(x) * (1-f(x))--(9) f(x)=(1+ex)2ex=f(x)(1f(x))(9)
标注:这种向后计算倒数的系统称为反向传播(backpropagation)
此时,我们以实际的数值带入进行计算:
由Alice的weight和height数据进行标准化后的数据可知:对于上述模型,实际的参数取值为:
x1 = -2, x2 = -1
w1 = w2 = w3 = w4 = w5 = w6 = 1
b1 = b2 = b3 = 0
所以:
h1 = f(x1w1 + x2w2 + b1) = 0.0474
h2 = f(x1w3 + x2w4 + b2) = 0.0474
o1 = f(w5h1 + w6h2 + b3) = f(0.0948) = 0.524
此时神经网络输出为y = 0.524,并没有明显的显示出男(0)和女(1)的证据匹配。
而此时∂L/∂w1为:
∂ L ∂ w 1 = x 1 ∗ f ′ ( w 1 x 1 + w 2 x 2 + b 1 ) ∗ w 5 ∗ f ′ ( w 5 h 1 + w 6 h 2 + b 3 ) ∗ ( − 2 ) ∗ ( 1 − y p r e d ) − − ( 10 ) \frac{\partial L}{\partial w1} = x1 * f^{'}(w1x1 + w2x2 + b1) * w5 * f^{'}(w5h1 + w6h2 + b3) * (-2) * (1 - y_{pred})--(10) w1L=x1f(w1x1+w2x2+b1)w5f(w5h1+w6h2+b3)(2)(1ypred)(10)
最终结果为:∂L/∂w1 = 0.0214
结论:增大w1,损失函数会有一个非常小的增长

随机梯度下降:

使用**随机梯度下降(SGD)**的优化算法训练神经网络。
SGD算法说明:定义了权重和偏置的自动调整的方法:
w 1 ← w 1 − η ∂ L ∂ w 1 − − ( 11 ) w1 \leftarrow w1 - \eta \frac{\partial L}{\partial w1} --(11) w1w1ηw1L(11)

参数说明:η是一个常数,被称作学习率(learning rate),决定了训练网络速率的快慢。上式是权重更新的方法。

训练流程如下:
1.数据集中挑选一个样本;
2.计算损失函数对所有权重和偏置的偏导数
3.更新每一个权重和偏置
4.回到第一步循环进行每一个训练实例的训练

python实现为:
模块导入及相关辅助函数

#模块导入
import numpy as np
import matplotlib.pyplot as plt
#sigmoid激活函数
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

#激活函数导数求解方式
def deriv_sigmoid(x):
    fx = sigmoid(x)

    return fx * (1 - fx)

#均方误差函数-损失
def mse_loss(y_true, y_pred):
    return ((y_true - y_pred) ** 2).mean()

训练神经网络(更新权重和偏置):

class OurNeuralNetwork:
    '''
    A neural network with:
    - 2 inputs
    - a hidden layer with neurons (h1, h2)
    - an output layer with 1 neuron (o1)
    '''
    def __init__(self):
        #weights
        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()
        
        #bias
        self.b1 = np.random.normal()
        self.b2 = np.random.normal()
        self.b3 = np.random.normal()
        
       
        
    def feedforward(self, inputs):
        #inputs为一个数组包含两个值
        h1_par = np.array([self.w1, self.w2])
        h2_par = np.array([self.w3, self.w4])
        o1_par = np.array([self.w5, self.w6])
        
        h1 = sigmoid(np.dot(h1_par, inputs) + self.b1)
        h2 = sigmoid(np.dot(h2_par, inputs) + self.b2)
        o1_inputs = np.array([h1, h2])
        o1 = sigmoid(np.dot(o1_par, o1_inputs) + self.b3)
        
       
        return o1
    
    def train_example(self, data, all_y_trues):
        '''
        - data 是一个(n * 2)的数组,n代表训练集的实例个数
        - all_y_trues是一个含有n个元素的数组
        '''
        #设定学习率
        learning_rate = 0.1
        loops = 1000#循环的次数
        loss_ypred = []
        loop_ypred = []
        
        for loop in range(loops):
            for x, y_true in zip(data, all_y_trues):
                
                 #参数向量化
                h1_par = np.array([self.w1, self.w2])
                h2_par = np.array([self.w3, self.w4])
                o1_par = np.array([self.w5, self.w6])
                
                h1 = sigmoid(np.dot(h1_par, x) + self.b1)
                h2 = sigmoid(np.dot(h2_par, x) + self.b2)
                o1_inputs = np.array([h1, h2])
                o1 = sigmoid(np.dot(o1_par, o1_inputs) + self.b3)
                
            
                #预测值就是o1
                y_pred = o1

                #计算偏导数
                d_L_d_ypred = -2 * (y_true - y_pred)

                #神经元o1涉及到的偏导数求解:
                d_ypred_d_w5 = h1 * deriv_sigmoid(np.dot(o1_par, o1_inputs))#∂y_pred/∂w5
                d_ypred_d_w6 = h2 * deriv_sigmoid(np.dot(o1_par, o1_inputs))#∂y_pred/∂w6
                d_ypred_d_b3 = deriv_sigmoid(np.dot(o1_par, o1_inputs))#∂y_pred/∂b3  

                d_ypred_d_h1 = self.w5 * deriv_sigmoid(np.dot(o1_par, o1_inputs))
                d_ypred_d_h2 = self.w6 * deriv_sigmoid(np.dot(o1_par, o1_inputs))

                #神经元h1涉及到的偏导数求解:
                d_h1_d_w1 = x[0] * deriv_sigmoid(np.dot(h1_par, x))
                d_h1_d_w2 = x[1] * deriv_sigmoid(np.dot(h1_par, x))
                d_h1_d_b1 = deriv_sigmoid(np.dot(h1_par, x))

                #神经元h2涉及到的偏导数求解
                d_h2_d_w3 = x[0] * deriv_sigmoid(np.dot(h2_par, x))
                d_h2_d_w4 = x[1] * deriv_sigmoid(np.dot(h2_par, x))
                d_h2_d_b2 = deriv_sigmoid(np.dot(h2_par, x))

                #进行权重和偏置的更新
                #神经元h1部分:
                self.w1 -= learning_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w1
                self.w2 -= learning_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w2
                self.b1 -= learning_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_b1

                #神经元h2部分:
                self.w3 -= learning_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_w3
                self.w4 -= learning_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_w4
                self.b2 -= learning_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_b2

                #神经元o1部分:
                self.w5 -= learning_rate * d_L_d_ypred * d_ypred_d_w5
                self.w6 -= learning_rate * d_L_d_ypred * d_ypred_d_w6
                self.b3 -= learning_rate * d_L_d_ypred * d_ypred_d_b3
            
            #计算损失的值
            if loop % 10 == 0:
                y_preds = np.apply_along_axis(self.feedforward, 1, data)
                loss = mse_loss(all_y_trues, y_preds)
                print('loop %d loss : %.3f' % (loop, loss))
                loss_ypred.append(loss)
                loop_ypred.append(loop)
                
        plt.rcParams['font.sans-serif']=['SimHei'] 
        plt.rcParams['font.serif'] = ['KaiTi']
        plt.rcParams['axes.unicode_minus'] = False#显示中文标签
        plt.plot(loop_ypred, loss_ypred, c = 'b', label = u'损失函数曲线')
        plt.xlabel(u'循环次数')
        plt.ylabel(u'损失值')
        plt.legend()
        plt.show()
#训练数据集  
data = np.array([
    [-2, -1],#Alice
    [25, 6],#Bob
    [17, 4],#Charlie
    [-15, -6],#Diana
])
all_y_trues = np.array([
    1,#Alice
    0,#Bob
    0,#Charlie
    1,#Diana
])

#训练神经网络
network = OurNeuralNetwork()
network.train_example(data, all_y_trues)

结果(部分):

loop 0 loss : 0.353
loop 10 loss : 0.229
loop 20 loss : 0.150
loop 30 loss : 0.105
loop 40 loss : 0.077
loop 50 loss : 0.059
loop 60 loss : 0.048
loop 70 loss : 0.039
loop 80 loss : 0.033
loop 90 loss : 0.029
loop 100 loss : 0.025

图示为:
在这里插入图片描述随机梯度下降算法总结:
1.部分函数用法详解:

#(1)numpy.random.normal()产生一个正态分布下的数值
#用法例子:
numpy.random.normal(loc=0,scale=1e-2,size=shape) 
#loc代表正态分布的均值。loc = 0代表这是一个以y轴为对称轴的正态分布
#scale代表正态分布的标准差。
#size代表生成数据的维数,默认是产生一个元素;例如:
a = numpy.random.normal(size = (2, 3))
#产生一个2*3维度的服从正态分布的数组


#(2)numpy.apply_along_axis(func, axis, arr, *args, **kwargs)--将arr数组中每一个元素经过func函数进行处理后生成一个新的数组
#用法例子:
numpy.apply_along_axis(self.feedforward, 1, data)
#如上述随机梯度下降法中的例子,即将data中每一个元素经过self.feedforward函数进行处理后返回一个数组
#func是我们写的一个函数
#axis表示函数func对arr是作用于行还是列
#arr便是我们要进行操作的数组了

#axis=1代表按行进行处理,axis=0代表按列进行处理
def solve(a):
    return a[0]
b = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
c = np.apply_along_axis(solve, 1, b)#此时c为array([1, 5, 9])
c = np.apply_along_axis(solve, 0, b)#此时c为array([1, 2, 3, 4])

#zip函数用法:
zip(a, b)#返回值为一个对象,需要list(zip(a, b))才能返回一个列表形式的压缩效果
zip(*zip(a, b))#解压,需要list(zip(a, b))才能返回一个列表形式的解压缩效果
#例子:
a = [[1, 2], [3, 4], [5, 6], [7, 8]]
b = [4, 5, 6, 7]
>list(zip(a, b))
#结果为:[([1, 2], 4), ([3, 4], 5), ([5, 6], 6), ([7, 8], 7)]
>list(zip(*zip(a, b)))
#结果为:[([1, 2], [3, 4], [5, 6], [7, 8]), (4, 5, 6, 7)]
>x1, x2 = list(zip(*zip(a, b)))
>print(list(x1), '\n', list(x2))
#结果为:[[1, 2], [3, 4], [5, 6], [7, 8]] 
 		[2, 3, 4, 5]
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值