神经网络入门学习笔记

一、概述

 虽然多重感知机可以实现复杂的函数,但是他的权重和偏置都是人工确定的,而神经网络的出现就是为了解决这个问题,神经网络就是可以自动地从数据中学习到合适的权重参数

二、神经网络的例子

在这里插入图片描述

我们把最左边的一列称之为输入层,最右边的一列称之为输出层,中间的一列称之为中间层,中间层有时候称之为隐藏层,从输入层到输出层一次称之为第0层,第1层,第2层

在这里插入图片描述

我们对比一下感知机,b作为偏置的参数,用于控制神经元被激活的容易程度,w1和w2表示每一个信号的权重和参数,用于控制每一个信号的重要性。

这里我们可以将b也作为权重,输入信号是1,这个感知机将x1,x2,1三个输入信号作为神经元的输入,将其和各自的权重相乘之后,传送至下一个神经元,在下一个神经元中,计算这些加权信号的总和。如果这个总和超过0,输入1,否则输出0。这里为了将激活操作和求和操作区分开,引入一个新的函数:

在这里插入图片描述

输入信号的总和被函数hx进行转换,转换之后的数值就是输出y

三、激活函数

上面的函数h(x)就是激活函数,激活函数的作用在于决定如何来激活输入信号的总和

上面的式子表示的激活函数以阈值为界,一旦输入超过阈值,就切换输出,这样的函数称之为阶跃函数,感知机使用的就是阶跃函数,神经网络使用的函数不是阶跃函数。

3.1 sigmoid函数

 神经网络中使用的一个函数就是sigmoid函数

在这里插入图片描述

神经网络中用sigmoid函数作为激活函数,进行信号的转换,转换之后的信号被传送给下一个神经元。

感知机和神经网络主要的区别就是激活函数

3.2 阶跃函数的实现


def step_function(x):
    y = x > 0
    return y.astype(np.int)  ## 将布尔类型的数组转换成int类型

这里,set_function(np.array([1.0,2.0]))

该函数需要传入一个np数组,因为神经元有多个输入信号。对numpy数组先进行不等号运算,数组的每一个元素都会进行不等号运算,生成一个布尔类型的数组,大于0的元素都被转换为TRUE,小于或者等于0的元素都转换为False,生成的数组y是一个布尔类型的数组,最后通过astype函数转换数据类型,传入的参数是np.int

3.3 阶跃函数的图形

import numpy as np
import matplotlib.pylab as plt

def step_function(x):
    y = x > 0

    return y.astype(np.int)

x = np.arange(-5.0,5.0,0.1)  ## 生成指定范围的数据
y = step_function(x)

plt.plot(x,y)
plt.ylim(-0.1,1.1) ## 指定y轴的范围
plt.show()

在这里插入图片描述

3.4 sigmoid函数的实现

在这里插入图片描述


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

x = np.array([-1.0,1.0,2.0])
sigmoid(x)

针对多个输入信号,我们需要在sigmoid函数中传入一个np数组,我们可以看到,传入的x是一个向量,但是函数里面的1都是标量,标量如何与向量进行计算,之所以,sigmoid函数的实现能支持numpy数组,秘密在于numpy数组的广播功能,根据numpy的广播功能,如果在标量和Numpy数组之间进行计算,则标量会和NUmpy数组的各个元素进行运算,np.exp(-x)会生成numpy数组,所以1 / 1 + np.exp(-x)的运算将会在numpy数组的各个元素之间进行

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

x = np.arange(-5.0,5.0,0.1)
y = sigmoid(x)

plt.plot(x,y)
plt.ylim(-0.1,1.1)
plt.show()

在这里插入图片描述

3.5 sigmoid函数和阶跃函数的比较

  • sigmoid函数是一条平滑的曲线,输出随着输入发生连续性的变化
  • 阶跃函数只能返回0或者1,sigmoid函数可以返回小数,也就是说感知机神经元之间流动的是01信号,神经网络中流动的是连续的实数值信号
  • 阶跃函数和sigmoid函数的共同点:不管输入信号多小或者多大,输出信号都在0和1之间

3.6 ReLU函数

 函数在输入大于0时,直接输出该值,在输入小于等于0时,输出0,

在这里插入图片描述

def relu(x):
    return np.maximum(0,x)

四、多维数组的运算

4.1 多维数组的概述

import numpy as np

A = np.array([1,2,3,4])

print(np.ndim(A))
A.shape

数组的维数通过np.ndim()函数来获得,数组的形状通过shape函数来获得,矩阵的点乘通过dot函数

A = np.array([[1,2],[3,4]])
B = np.array([[5,6],[7,8]])

print(np.dot(A,B))

五、神经网络的设计

5.1 神经网络的内积

在这里插入图片描述

实现神经网络的时候,要注意X,W,Y的形状,尤其是注意XW的形状

X = np.array([1,2])
X.shape

W = np.array([[1,2,3],[2,4,6]])

W.shape

Y = np.dot(X,W)
print(Y)

5.2 三层神经网络的实现

在这里插入图片描述

该神经网络:输入层两个神经元,隐藏层(第一层):三个神经元,隐藏层(第二层):两个神经元,输出层:两个神经元

5.2.1 符号确认

在这里插入图片描述

上图显示了从输入层神经元x2到后一层神经元a1的权重w12,右上角的(1)表示权重和神经元的层号(即第一层的权重,第一层的神经元),权重右下角有两个数字,他们是后一层神经元和前一层神经元的索引号,比如w12表示前一层的第二个神经元x2到后一层的第一个神经元a1的权重。

5.2.2 各层神经元之间的实现

在这里插入图片描述

从输入层到第一层的实现:偏置也作为输入信号

在这里插入图片描述

下面实现输入层到隐藏层第一层:

X = np.array([1.0,0.5])
W1 = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])
B1 = np.array([0.1,0.2,0.3])

A1 = np.dot(X,W1) + B1
print(A1) # 1 x 3 矩阵

# 激活
Z1 = sigmoid(A1)
print(Z1)

下面实现第一层到第二层的信号传递:

W2 = np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
B2 = np.array([0.1,0.2])

A2 = np.dot(Z1,W2) + B2
print(A2)

Z2 = sigmoid(A2)

实现第二层到输出层的信号传递:

def identity_function(x):
 
    return x

W3 = np.array([[0.1,0.3],[0.2,0.4]])
B3 = np.array([0.1,0.2])

A3 = np.dot(Z2,W3) + B3
Y = identity_function(A3)
print(Y)

5.2.3 代码实现小节
## 初始化参数和偏置
def init_network():
    network = {}
    network['w1'] = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])
    network['b1'] = np.array([0.1,0.2,0.3])
    network['w2'] = np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
    network['b2'] = np.array([0.1,0.2])
    network['w3'] = np.array([[0.1,0.3],[0.2,0.4]])
    network['b3'] = np.array([0.1,0.2])
    return network

def forward(network,x):
    W1,W2,W3 = network['w1'],network['w2'],network['w3']
    b1,b2,b3 = network['b1'],network['b2'],network['b3']
    a1 = np.dot(x,W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1,W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2,W3) + b3
    z3 = identity_function(a3)
    return z3

network = init_network()
x = np.array([1.0,0.5])
y = forward(network,x)
print(y)

 这里定义了init_network()和forward()函数,init_network()函数会进行权重和偏置的初始化,并将它们保存在字典变量Network中,这个字典变量Network中保存了每一层所需要的参数(权重和偏置),forward()函数中则封装了将输入信号转换为输出信号的处理过程。

 这里的forward函数,他表示的是从输入到输出方向传递处理,后面在进行神经网络的训练时,我们将介绍后向(backward,从输出到输入方向)的处理

六、输出层的设计

6.1 softmax函数

回归问题使用恒等函数,分类问题使用softmax函数

softmax函数实现:

def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a - c)  ## 溢出对策
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a


    return y


a = np.array([0.3,2.9,4.0])
y = softmax(a)

print(y)

softmax函数的特征:

  • softmax函数的输出总是0.0到1.0之间的实数,并且softmax函数的输出值总和是1
  • 输出总和是1
  • 即便使用了softmax函数,各个元素之间的大小关系也不会改变,因为指数函数也是单调递增的
  • 神经网络只把输出值最大的神经元所对应的泪飙作为识别结果,即便是用softmax函数,输出值最大的神经元的位置也不会改变

6.2 输出层的神经元数量

 输出层神经元数量需要根据解决的问题来决定,对于分类问题,输出层的神经元数量一般设定为类别的数量

七、手写数字识别

7.1 MNIST数据集

 这里使用的数据集是MNIST手写数字图像集,MNIST数据集是由0-9数字图像构成的,训练图像六万张,测试图像一万张,每一张图像都是28x28x1(灰度),各个像素值取值在0~255之间。每一张图像对应相应的数字标签

打印训练数据和标签 测试数据和标签的形状

import sys,os
sys.path.append(os.pardir)  ## 为了导入父目录种的文件进行的设定
import numpy as np
import os
from PIL import Image
from dataset.mnist import load_mnist

## 导入训练数据
(x_train,t_train),(x_test,t_test) = load_mnist(flatten=True,normalize=False)

## 输出数据的形状
print(x_train.shape)
print(t_train.shape)
print(x_test.shape)
print(t_test.shape)
(60000, 784)
(60000,)
(10000, 784)
(10000,)

训练数据是60000张照片,每一张照片都是一个一维数组

load_mnist函数以(训练图像,训练标签)、(测试图像,测试标签)的形式返回读入的MNIST数据。

load_mnist(normalize = True,flatten = True,one_hot_label = False) 设置三个参数:第一个参数将输入图像正规化0~1,第二个参数:展开图像形成一个一维数组,那么输入图像会保存成一个784个元素的一维数组,第三个参数设置是否将标签保存为one-hot表示(正确标签为1,其余都是0)

加载第一张图像

import sys,os
sys.path.append(os.pardir)  ## 为了导入父目录种的文件进行的设定
import numpy as np
import os
from PIL import Image
from dataset.mnist import load_mnist

## 导入训练数据
(x_train,t_train),(x_test,t_test) = load_mnist(flatten=True,normalize=False)

## 输出数据的形状
print(x_train.shape)
print(t_train.shape)
print(x_test.shape)
print(t_test.shape)

def img_show(img):
    ## 将Numpy数组的图像数据转换为PIL用的数据对象
    pil_img = Image.fromarray(np.uint8(img))
    pil_img.show()

## 取出训练数据第一张图像
img = x_train[0]
label = t_train[0]
print(label)

img = img.reshape(28,28) ## 回复图像尺寸
img_show(img)

 需要注意的是,我们读取的图象是一个一维数组,所以显示图像的时候,需要将他恢复成原来的28x28尺寸图像,另外还需要将保存为Numpy数组的图像数据转换为PIL用的数据对象。

7.2 神经网络的推理处理

 神经网络的输入层有784个神经元,输出层10个神经元,输入层的神经元个数784来源于图像大小(28x28),输入层10来源于图像分类个数,另外神经网络有2个隐藏层,第一个隐藏层50个神经元,第二个隐藏层100个神经元

from copyreg import pickle
import sys,os
import pickle
from sklearn.metrics import accuracy_score

from torch import softmax
sys.path.append(os.pardir)  ## 为了导入父目录种的文件进行的设定
import numpy as np
import os
from PIL import Image
from dataset.mnist import load_mnist

## 导入训练数据
(x_train,t_train),(x_test,t_test) = load_mnist(flatten=True,normalize=False)

## 输出数据的形状
print(x_train.shape)
print(t_train.shape)
print(x_test.shape)
print(t_test.shape)

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

def img_show(img):
    ## 将Numpy数组的图像数据转换为PIL用的数据对象
    pil_img = Image.fromarray(np.uint8(img))
    pil_img.show()

## 取出训练数据第一张图像
img = x_train[0]
label = t_train[0]
print(label)

# img = img.reshape(28,28) ## 回复图像尺寸
# img_show(img)


def get_data():
    (x_train,t_train),(x_test,t_test) = load_mnist(normalize=True,flatten=True,one_hot_label=False)

    return x_test,t_test


## 读取学习到的权重参数
def init_network():
    with open("sample_weight.pkl","rb") as f:
        network = pickle.load(f)
    return network


def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a - c)  ## 溢出对策
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a


    return y
def predict(network,x):
    W1,W2,W3 = network['W1'],network['W2'],network['W3']
    b1,b2,b3 = network['b1'],network['b2'],network['b3']

    a1 = np.dot(x,W1)  + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1,W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2,W3) + b3
    y = softmax(a3)

    return y

x,t = get_data() ## 加载
network = init_network()  ## 加载参数

## 计算正确分类个数
accuracy_cnt = 0
for i in range(len(x)):
    y = predict(network,x[i])
    p = np.argmax(y) ## 获取改了最高的元素的索引

    if p == t[i]:
        accuracy_cnt += 1

print("Accuracy:" + str(float(accuracy_cnt) / len(x)))

上述代码:首先获得MNIST数据集,生成网络,然后使用for语句逐个取出保存在x中的图像数据,使用predict()函数进行分类,predict()函数以NuMPY数组的形式输出各个标签对应的概率,然后使用np.argmax(x)函数取出数组中的最大值的索引,np.argmax(x)将获取被赋给参数x的数组中的最大值元素的索引,最后,比较神经网络所预测的答案和正确的解标签,将回答正确的概率作为识别精度

7.3 批处理

在这里插入图片描述

 输入一个由784个元素(原本是一个28x28的二维数组)构成的一维数组后,输出一个有10个元素的一维数组

考虑打包输入多张图像的情况:

在这里插入图片描述

输入数据的形状是100x 784,输出数据的形状为100 x 10

x,t = get_data()
network = init_network()

batch_size = 100 ## 批数量
accuracy_count = 0

## 指定步长
for i in range(0,len(x),batch_size):
    x_batch = x[i:i + batch_size]
    y_batch = predict(network,x_batch)
    p = np.argmax(y_batch,axis = 1)  ## 指定第二维度
    accuracy_count += np.sum(p == t[i:i + batch_size])


print("Accuracy:" + str(float(accuracy_cnt) / len(x))) 

这里通过argmax()获取值最大的元素的索引,这里给定的参数axis = 1,指定第一维方向,最后使用比较运算符生成布尔数组,计算True个数

总结:批处理一次性计算大型数组要比分开逐步计算
各个小型数组速度更快

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少写代码少看论文多多睡觉

求打赏,求关注,求点赞

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值