写点什么

与 DeepLearning 的初次接触(上)

  • 2019-09-27
  • 本文字数:7929 字

    阅读完需:约 26 分钟

与 DeepLearning 的初次接触(上)

随着人工智能近十年来的飞速发展,机器学习、深度学习已从学术研究逐步落实到工业界,特别是近几年机器学习框架,如 TensorFlow、Pytorch、CNTK、Keras 等层出不穷,框架设计越来越面向开发者,特别是 TensorFlow.js 的发布、V8 引擎更高性能新版本的发布等等信息,这些好像在告诉我,将深度学习广泛应用到端已然不远了。

为了不被类似 Alpha 狗等 AI 打败,作为一名程序开发者,学习和了解一些机器学习的知识、最新动态信息还是有必要的,而深度学习作为机器学习的一部分,在工业界已经发挥了重要的作用,所以今天就由浅入深,从理论知识到实战编程,逐步探究人工神经网络为何物。

阅读提示

以下内容面向深度学习初学者,需要具备以下基本素质:

①有任何编程语言的编程经验

②对几何代数相关数学知识有基本理解

③对 TensorFlow、Keras 有所了解(不了解也不会有太大影响)

④对 Jupyter Notebook 有所了解(不了解也不会有太大影响)

内容纲要

以下内容分为四个章节,可能需要 30 分钟阅读时间

第一章节——介绍神经网络重要概念和数学推导

第二章节——实战编写逻辑回归模型

第三章节——使用 TensorFlow 实现浅层神经网络

第四章节——使用 Keras 实现深度神经网络

实战编程内容均通过 Jupyter Notebook 承载。

第一章理清神经网络的基础以及实现步骤

感知机

感知器(英语:Perceptron)是 Frank Rosenblatt 在 1957 年就职于康奈尔航空实验室(Cornell Aeronautical Laboratory)时所发明的一种人工神经网络。它可以被视为一种最简单形式的前馈神经网络,是一种二元线性分类器。


Frank Rosenblatt 给出了相应的感知机学习算法,常用的有感知机学习、最小二乘法和梯度下降法。譬如,感知机利用梯度下降法对损失函数进行极小化,求出可将训练数据进行线性划分的分离超平面,从而求得感知机模型。


**生物学-神经细胞**


!



(神经细胞结构示意图)


感知机是生物神经细胞的简单抽象。神经细胞结构大致可分为:树突、突触、细胞体及轴突。单个神经细胞可被视为一种只有两种状态的机器——激动时为‘是’,而未激动时为‘否’。神经细胞的状态取决于从其它的神经细胞收到的输入信号量,及突触的强度(抑制或加强)。当信号量总和超过了某个阈值时,细胞体就会激动,产生电脉冲。电脉冲沿着轴突并通过突触传递到其它神经元。为了模拟神经细胞行为,与之对应的感知机基础概念被提出,如权量(突触)、偏置(阈值)及激活函数(细胞体)。


**人工神经元**


!



(神经元结构示意图)


在人工神经网络领域中,感知机也被指为单层的人工神经网络,以区别于较复杂的多层感知机(Multilayer Perceptron)。作为一种线性分类器,(单层)感知机可说是最简单的前向人工神经网络形式。尽管结构简单,感知机能够学习并解决相当复杂的问题。感知机主要的本质缺陷是它不能处理线性不可分问题。

(注:以上内容摘自维基百科)


单层感知机的适用和缺陷


适合解决线性问题,如下图



无法解决线性不可分,如常见的 XOR 异或问题,如下图


二分类

目前工业界最能产生价值的是机器学习中的监督学习, 场景有推荐系统,反欺诈系统等等。其中二分类算法应用的尤其之多。



例如上面的图像识别场景, 我们希望判断图片中是否有猫,于是我们为模型输入一张图片,得出一个预测值 y。 y 的取值为 1 或者 0. 0 代表是,1 代表否。

逻辑回归模型

逻辑回归是一个用于二分类(binary classification)的算法。



逻辑回归的 Hypothesis Function(假设函数)



sigmoid 函数



逻辑回归的输出函数



激活函数


也叫激励函数,是为了能够给神经网络加入一些非线性因素,使得神经网络可以更好地解决较为复杂的问题。


常见的激活函数


Sigmoid 函数


tanh 函数


ReLU 函数



损失函数(Lost Function)



代价函数(Cost Function)


为了训练逻辑回归模型的参数参数𝑤和参数𝑏,我们需要一个代价函数,通过训练代价函数来得到参数𝑤和参数𝑏。


代价函数也叫做成本函数,也有人称其为全部损失函数。


损失函数是在单个训练样本中定义的,它衡量的是算法在单个训练样本中表现如何,为了衡量算法在全部训练样本上的表现如何,我们需要定义一个算法的代价函数。


算法的代价函数是对个 m 样本的损失函数求和,然后除以 m:



损失函数只适用于像这样的单个训练样本,而代价函数是参数的总代价,所以在训练逻辑回归模型时候,我们需要找到合适的和,来让代价函数 的总代价降到最低。


代价函数的解释



由上述推论可得出这两个条件概率公式:



以下类似手写截图均来自吴恩达老师的深度学习课程


可将上述公式,合并成如下公式:



解释合并过程




推导到 m 个训练样本的整体训练的代价函数


计算图

计算图是什么


一个神经网络的计算,都是按照前向或反向传播过程组织的。



首先我们计算出一个新的网络的输出(前向过程),紧接着进行一个反向传输操作。后者我们用来计算出对应的梯度或导数。


计算图解释了为什么我们用这种方式组织这些计算过程。


举例说明



概括一下:计算图组织计算的形式是用蓝色箭头从左到右的计算


使用计算图求导数


进行反向红色箭头(也就是从右到左)的导数计算



在反向传播算法中的术语,我们看到,如果你想计算最后输出变量的导数,使用你最关心的变量对𝑣的导数,那么我们就做完了一步反向传播。


当计算所有这些导数时,最有效率的办法是从右到左计算,跟着这个红色箭头走。


所以这个计算流程图,就是正向或者说从左到右的计算来计算成本函数 J(你可能需要优化的函数)。然后反向从右到左是计算导数。

梯度下降

梯度下降法 (Gradient Descent)


梯度下降法可以做什么?


在你测试集上,通过最小化代价函数(成本函数)𝐽(𝑤, 𝑏)来训练的参数𝑤和𝑏



梯度下降法的形象化说明



在这个图中,横轴表示你的空间参数𝑤和𝑏,在实践中,𝑤可以是更高的维度,但是为了 更好地绘图,我们定义𝑤和𝑏,都是单一实数,代价函数(成本函数)𝐽(𝑤, 𝑏)是在水平轴𝑤和 𝑏上的曲面,因此曲面的高度就是𝐽(𝑤, 𝑏)在某一点的函数值。我们所做的就是找到使得代价 函数(成本函数)𝐽(𝑤, 𝑏)函数值是最小值,对应的参数𝑤和𝑏。


以如图的小红点的坐标来初始化参数𝑤和𝑏。



选出最陡的下坡方向,并走一步,且不断地迭代下去。


朝最陡的下坡方向走一步,如图,走到了如图中第二个小红点处。



可能停在这里也有可能继续朝最陡的下坡方向再走一步,如图,经过两次迭代走到 第三个小红点处。



直到走到全局最优解或者接近全局最优解的地方。



通过以上的三个步骤我们可以找到全局最优解,也就是代价函数(成本函数)𝐽(𝑤, 𝑏)这个凸函数的最小值点。


逻辑回归的梯度下降



反向传播计算 𝑤 和 𝑏 变化对代价函数 𝐿 的影响



单个样本的梯度下降算法



网络向量化


我们已经了解了单个训练样本的损失函数,当使用编程进行计算多个训练样本的代价函数时,一般都会想到使用 loop 循环来计算。


但是在数学科学领域,训练一个模型可能需要非常大量的训练样本, 即大数据集,使用 loop 循环遍历的方式是十分低效的。


线性代数的知识起到了作用,我们可以通过将循环遍历的样本数据,进行向量化,更直接的、更高效的计算,提高代码速度,减少等待时间,达到我们的期望。


注意:虽然有时写循环(loop)是不可避免的,但是我们可以使用比如 numpy 的内置函数或者其他办法去计算。



神经网络实现步骤


在深度学习中,我们一般都会使用第三方框架,如 TensorFlow, Keras,训练过程对我们来说是不可见的。


上面讲了很多的函数、以及其概念、作用,这些神经网络的”组件“,或者说,”组成部分“,如何串联起来呢?以及为什么一开始就会提到 ”前向传播“ 和 ”后向传播“ 这两个概念?


在一个简单神经网络的实现中,简化分为几步:


1、引入外部包


2、加载数据集


3、定义计算图


4、初始化参数


5、一次迭代的前向传播:执行计算图,一层层计算,直到计算到输出层,得到预估值、准确率、损失函数


6、一次迭代的反向传播:对上次得到损失函数求导,使用优化函数(梯度下降算法)从右向左对神经网络的每一层计算调参,直到计算到第一个隐含层,得到优化更新的参数


7、重复(5)(6)为一个迭代,记录多个迭代的信息,训练完毕的模型的最终损失和准确率。


8、使用(7)中得到的训练过程数据,绘制训练集、测试集关于迭代次数与损失的关系曲线图以及迭代次数与准确率关系的曲线图,进行分析,以调整超参数。

第二章逻辑回归(Logistic Regression)实现猫咪识别器

导入所需的 package


import numpy as npimport matplotlib.pyplot as pltimport h5pyfrom PIL import Imagefrom loadH5File import load_data
%matplotlib inline
复制代码


加载数据集 (cat / non-cat)


train_set_x, train_set_y, test_set_x, test_set_y, classes = load_data()
复制代码


train_x (209, 64, 64, 3) test_x (50, 64, 64, 3)train_y (1, 209) test_y (1, 50)
复制代码

查阅训练集中的一张图片

一张正确分类的图片


index = 7plt.imshow(train_set_x[index])print ("y = " + str(train_set_y[:,index]) + ", it's a '" + classes[np.squeeze(train_set_y[:,index])].decode("utf-8") +  "' picture.")
复制代码


y = [1], it's a 'cat' picture.
复制代码



一张错误分类的图片


index = 10plt.imshow(train_set_x[index])print ("y = " + str(train_set_y[:,index]) + ", it's a '" + classes[np.squeeze(train_set_y[:,index])].decode("utf-8") +  "' picture.")
复制代码


y = [0], it's a 'non-cat' picture.png
复制代码


猫咪图片数据处理过程示意


实现输入数据扁平变形和标准化(也叫归一化)


将训练集和测试集中的 x 维度切分为(num_px * num_px * 3, m)的形式


reshape 目的:实现矩阵乘法计算


  • x 维度切分为(num_px * num_px * 3, m)的形式。

  • y 维度切分为(1, m)的形式。


标准化目的:预处理的数据被限定在一定的范围内(比如[0,1]或者[-1,1]),从而消除奇异样本数据导致的不良影响。


num_px = train_set_x.shape[1]m_train = train_set_x.shape[0]m_test = test_set_x.shape[0]
# 重塑输入数据train_x_flatten = train_set_x.reshape(train_set_x.shape[0], -1).Ttest_x_flatten = test_set_x.reshape(test_set_x.shape[0], -1).T
print('train_x', train_x_flatten.shape, 'test_x', test_x_flatten.shape) print('train_y', train_set_y.shape, 'test_y', test_set_y.shape)
# 标准化输入数据train_set_x = train_x_flatten/255test_set_x = test_x_flatten/255
复制代码


train_x (12288, 209) test_x (12288, 50)train_y (1, 209) test_y (1, 50)
复制代码


实现激活函数



def sigmoid(z):    '''    计算 z 的非线性输出值
Arguments: z -- 一个标量或者一个 numpy array
Return: s -- sigmoid(z) ''' s = 1 / (1 + np.exp(-z))
return s
复制代码

实现初始化参数函数

如图小红点的坐标来初始化参数𝑤和𝑏。



def initialize_with_zeros(dim):    """    将 w 构造为一个 shape 为 (dim, 1) 的零值向量,将 b 设置为 0
Argument: dim -- 行向量 w 的大小
Returns: w -- 初始化后的行向量, shape 为 (dim, 1) b -- 初始化后的标量 (表示偏差) """
w = np.zeros(shape=(dim, 1)) b = 0
assert(w.shape == (dim, 1)) assert(isinstance(b, float) or isinstance(b, int))
return w, b
复制代码


实现代价函数(前向传播)和梯度下降函数(反向传播)


前向传播



反向传播



def propagate(w, b, X, Y):    '''    实现前向传播和反向传播
Arguments: w -- 权重, 一个行向量 (num_px * num_px * 3, 1) b -- 偏差, 一个标量 X -- 标准化后的 X 矩阵 (num_px * num_px * 3, number of examples)
Return: cost -- 逻辑回归的成本函数(负值) dw -- w 的梯度下降,shape 同 w db -- b 的梯度下降,shape 同 b
''' m = X.shape[1]
# 前向传播 A = sigmoid(np.dot(w.T, X) + b) cost = -1 / m * np.sum(Y * np.log(A) + (1-Y) * np.log(1-A))
# 反向传播 dw = 1 / m * np.dot(X, (A-Y).T) db = 1 / m * np.sum(A-Y)
assert(dw.shape == w.shape) assert(db.dtype == float) cost = np.squeeze(cost) assert(cost.shape == ())
grads = {"dw": dw, "db": db}
return grads, cost
复制代码

实现调参函数

以梯度下降算法不断更新参数,使其达到更优。



def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost = False):    '''    运行梯度下降算法,优化调整 w, b 参数
Arguments: w -- 权重, 一个行向量 (num_px * num_px * 3, 1) b -- 偏差, 一个标量 X -- 标准化后的 X 矩阵,shape 为 (num_px * num_px * 3, number of examples) Y -- 一个由 0, 1 组成(其中 0 表示 non-cat, 1 表示 cat)的列向量, shape 为 (1, number of examples) num_iterations -- 迭代次数/优化更新次数 learning_rate -- 梯度下降的学习率/更新步长 print_cost -- 是否打印损失,默认不打印
Returns: params -- 一个包含了权重 w 和 偏差 b 的字典 grads -- 一个包含了权重 w 和 偏差 b 的梯度的字典 costs -- 一个保留了所有更新计算过的损失值的列表,用于绘制学习曲线 '''
costs = []
for i in range(num_iterations):
# 调用 propagate 函数计算 w, b 的梯度以及损失 grads, cost = propagate(w, b, X, Y)
dw = grads["dw"] db = grads["db"]
# 更新 w, b,优化调整参数 w = w - learning_rate * dw b = b - learning_rate * db
# 保存当次更新的损失 if i % 100 == 0: costs.append(cost)
# 每训练100次,打印一次损失 if print_cost and i % 100 == 0: print("Cost after iteration %i: %f" % (i, cost))
params = {"w": w, "b": b}
grads = {"dw": dw, "db": db}
return params, grads, costs
复制代码


2019-09-27 13:041176

评论

发布
暂无评论
发现更多内容

用NineData三分钟搭建企业数据库平台,告别数据泄露与删库跑路

NineData

安全 敏感数据 AIGC 玖章算术 NineData

3步带你搞定华为云编译构建CodeArts Build “新手村任务”

华为云开发者联盟

云计算 后端 华为云 华为云开发者联盟 企业号 7 月 PK 榜

搜狗输入法双击输入框崩溃问题 | 京东云技术团队

京东科技开发者

搜索引擎 搜索 输入法 企业号 7 月 PK 榜

全国独家线下面授 | 上海大规模敏捷LeSS认证9月7-9日

ShineScrum

less 大规模敏捷 大规模敏捷LeSS CLP

Ceph社区上游正式合入openEuler原生支持,并通过CI持续验证

openEuler

Linux 分布式 操作系统 Ceph openEuler

Nautilus Chain 主网上线,Zepoch 持有者将获第三轮 POSE 空投

西柚子

Nautilus Chain 主网上线,Zepoch 持有者将获第三轮 POSE 空投

西柚子

详解TCP网络协议栈的工作原理

华为云开发者联盟

后端 开发 华为云 华为云开发者联盟 企业号 7 月 PK 榜

功能更新|Leangoo领歌敏捷工具支持SAFe大规模敏捷框架

顿顿顿

敏捷开发 敏捷项目管理 scrum敏捷工具 SAFe框架 SAFe大规模敏捷

《Spring6核心源码解析》已完结,涵盖IOC容器、AOP切面、AOT预编译、SpringMVC,面试杠杠的!

冰河

Java spring 程序员 架构师 源码解析

云原生网关部署新范式丨 Higress 发布 1.1 版本,支持脱离 K8s 部署

阿里巴巴云原生

阿里云 云原生 Higress

在 Go 语言单元测试中如何解决 HTTP 网络依赖问题

江湖十年

单元测试 HTTP Go 语言

统一观测丨使用 Prometheus 监控 Cassandra 数据库最佳实践

阿里巴巴云原生

阿里云 云原生 Prometheus

AIGC技术展望和机会 | 社区征文

AIWeker

AIGC Stable Diffusion MidJourney 年中技术盘点

不止工具:音视频开发「利器」的新机遇

阿里云CloudImagine

云计算 音视频 视频云

火山引擎DataLeap如何解决SLA治理难题(三): 平台架构与未来展望

字节跳动数据平台

大数据 数据中台 数据治理 数据安全 企业号 7 月 PK 榜

防范直播网站源码搭建多重问题的背后重要功能_山东布谷科技创作

山东布谷科技

软件开发 直播 源码搭建 直播源码 直播网站源码

新一轮智能制造相关产业政策猜想

华为云开发者联盟

云计算 后端 华为云 华为云开发者联盟 企业号 7 月 PK 榜

Nautilus Chain 主网上线,Zepoch 持有者将获第三轮 POSE 空投

BlockChain先知

关于云平台虚拟机核心组件 libvirt 热迁移流程及关键参数介绍 | 龙蜥技术

OpenAnolis小助手

开源 虚拟机 龙蜥大讲堂 浪潮数据 热迁移

三大升级!龙蜥正式推出首款全面拥抱智算的国产操作系统 Anolis OS 23

OpenAnolis小助手

开源 操作系统 龙蜥社区 版本发布 Anolis23

技术速览|Meta Llama 2 下一代开源大型语言模型

SEAL安全

meta openai backstage mata llama

IoT 场景下 InfluxDB 与 TDengine 的性能对比测试报告出炉!点击查看

爱倒腾的程序员

数据库

Dxitco德西科跟单社区首创CHATGPT人工+AI双重大数据分析机制

科技热闻

《让花掉的钱自己流回来》

石云升

读书笔记 财富管理

SAM&Stable-Diffusion集成进化!分割、生成一切!AI绘画新玩法

飞桨PaddlePaddle

人工智能 百度 paddle AI 飞桨

如何评价一种框架技术的好坏?

canonical

低代码 架构设计 软件设计原则 ORM框架 开源框架

Excel 高阶使用(含 ChatGPT)与数据可视化

Data 探险实验室

数据分析 Excel 数据可视化 可视化工具 ChatGPT

上海科技大学智能生活组齐聚合合信息,“沉浸式”体验人工智能产品

合合技术团队

人工智能 人才发展 合合信息 校企合作 上海科技大学

2023 云原生编程挑战赛火热报名中!导师解析 Serverless 冷启动赛题

阿里巴巴云原生

阿里云 Serverless 云原生

Spring 中一个少见的引介增强 IntroductionAdvisor

江南一点雨

Java spring

与 DeepLearning 的初次接触(上)_AI&大模型_江伯_InfoQ精选文章