Shu's Garden - Softmax
type: channel
link: https://www.sitstars.com/tag/Softmax/
items: PaddlePaddle飞桨课程学习Day3-5：手写数字识别与CNN
items: 0基础入门神经网络：递归神经网络(RNN)
items: 0基础入门神经网络：卷积神经网络(CNN)02
items: 0基础入门神经网络：卷积神经网络(CNN)01

PaddlePaddle飞桨课程学习Day3-5：手写数字识别与CNN
type: item
date: 2020-08-16T15:05:10+08:00
description: 前言：手写数字识别如果说波士顿房价预测是机器学习中的hello world,，那么手写数字识别就是深度学习中的hello world。在处理如下图所示的手写邮政编码的简单图像分类任务时，可以使用基于MNIST数据集的手写数字识别模型。MNIST是深度学习领域标准、易用的成熟数据集，包含60000条训练样本和10000条测试样本。 任务输入：一系列手写数字图片，其中每张图片都是28x28的像素矩阵。任务输出：经过了大小归一化和居中处理，输出对应的0~9的数字标签。本次任务使用的网络模型为卷积神经网络（CNN），它被广泛应用于图像识别，自然语言等领域。该任务同样遵循五步走战略，即数据处理—模型设计—训练配置—训练过程—模型保存 极简版本的实现代码import paddle import paddle.fluid as fluid from paddle.fluid.dygraph.nn import Linear import numpy as np import os from PIL import Image class MNIST(fluid.dygraph.Layer): def __init__(self): super(MNIST,self).__init__() # 定义一层全连接层，输出维度1，激活函数None self.fc = Linear(input_dim = 784,output_dim=1) # 前向计算 def forward(self,inputs): outputs = self.fc(inputs) return outputs # 创建动态图工作环境 with fluid.dygraph.guard(): # 声明网络结构 model = MNIST() # 启动训练模式 model.train() # 定义读取函数 train_loader = paddle.batch(paddle.dataset.mnist.train(),batch_size=16) # 定义优化器，使用SGD，学习率设置为0.001 optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.001,parameter_list=model.parameters()) epoch_num = 10 # 10次大循环 for epoch in range(epoch_num): for batch_id,data in enumerate(train_loader()): # 数据格式转换 img_data = np.array([x[0] for x in data]).astype("float32") label_data = np.array([x[1] for x in data]).astype("float32").reshape(-1,1) # 为了loss计算，最后一维要是1。-1是占位符，这个位置是为了batch_size预留的 # 将数据转为飞桨动态图格式 img = fluid.dygraph.to_variable(img_data) label = fluid.dygraph.to_variable(label_data) # 前向计算 predict = model.forward(img) # 计算损失 loss = fluid.layers.square_error_cost(predict,label) avg_loss = fluid.layers.mean(loss) # 每训练1000次数据就打印一次 if batch_id != 0 and batch_id % 1000 == 0: print("epoch is {},batch is {}, loss is {}".format(epoch,batch_id,avg_loss.numpy())) # 后向传播 avg_loss.backward() # 更新参数 optimizer.minimize(avg_loss) # 最小化损失 model.clear_gradients() # 清除梯度 # 保存模型 fluid.save_dygraph(model.state_dict(), 'mnist')说明：飞桨提供了多个封装好的数据集API，涵盖计算机视觉、自然语言处理、推荐系统等多个领域，帮助读者快速完成深度学习任务。如在手写数字识别任务中，通过paddle.dataset.mnist可以直接获取处理好的MNIST训练集、测试集。飞桨将维度是28*28的手写数字图像转成向量形式存储，因此使用飞桨数据加载器读取到的手写数字图像是长度为784（28*28）的向量。pa…

0基础入门神经网络：递归神经网络(RNN)
type: item
date: 2019-10-24T00:11:00+08:00
description: 原文地址为什么使用RNN？递归神经网络（Recurrent Neural Networks，RNN）是一种专门处理序列的神经网络。由于它们在处理文本方面的有效性，因此经常用于自然语言处理（NLP）任务。在本文中，我们将探讨RNN是什么，了解它们的工作原理，并在Python中从头开始构建一个真正的RNN。（仅使用numpy）。这篇文章假定您具有神经网络的基础知识。建议先阅读神经网络基础最原始（vanilla，原意为香草，在机器学习中等同于raw）的神经网络和CNNs存在一个问题：只能接受固定的输入并产生固定的输出。RNN则不同，它可以接受并输出可变长度序列，以下是RNN的一些例子： 输入为红色，RNN本身为绿色，输出为蓝色。资料来源：Andrej Karpathy这种处理序列的能力使RNN非常有用。例如：机器翻译（例如Google Translate）使用“多对多” 型RNN进行。原始文本序列输送到RNN，然后RNN生成翻译后的文本并输出。情绪分析（例如，这是正面还是负面的评价？）通常使用“多对一”的RNN进行。将要分析的文本输入到RNN中，然后生成一个单一的输出分类（例如，这是正面的评价）。在本文的后半部分，我们将构建一个“多对一”式的RNN，实现一个最简单的情感分析功能如何做？让我们考虑一个“多对多”式的RNN，它接受$x _ { 0 } , x _ { 1 } , \dots x _ { n }$的输入，并产生$y _ { 0 } , y _ { 1 } , \dots y _ { n }$的输出，xi和yi可以是任意维度的向量。RNN借助一个迭代更新的 隐状态（hidden state）h来工作，h也是一个任意维度的向量。在任意给定的步长t上，有：下一个 隐状态$h_t$通过先前的 隐状态$h_{t-1}$和下一个输入 $x_t$计算而来。下一个输出$y_t$由$h_t$计算而来。 一个多对多RNN这就是使RNN 反复出现的原因：它对每个步骤使用相同的权重。更具体地说，典型的原始RNN仅使用3组权重来执行其计算：$W_{xh}$用于所有的$x_t\to h_t$链接$W_{hh}$用于所有的$h_{t-1}\to h_t$链接$W_{hy}$用于所有的$h_t\to y_t$链接同时我们为RNN应用两个偏置（biases）：$b_h$，计算$h_t$的时候需要加上它。$b_y$，计算$y_t$的时候需要加上它。我们用矩阵表示权重，用向量表示偏置。这3个权重和2个偏置构成了整个RNN！以下是将所有内容组合在一起的方程式：$$\begin{array} { c } { h _ { t } = \tanh \left( W _ { x h } x _ { t } + W _ { h h } h _ { t - 1 } + b _ { h } \right) } \\ { y _ { t } = W _ { h y } h _ { t } + b _ { y } } \end{array}$$不要跳过这些方程式。停下来思考一下。另外，请记住，权重是矩阵，其他变量是向量。所有的权重都使用矩阵乘法，并且将偏置加到乘积结果中。然后，我们将tanh用作第一个方程式的激活函数（但是也可以使用S型等其他激活函数）。问题我们将从头开始实现RNN，以执行简单的情感分析任务：确定给定的文本字符串是正面的还是负面的。这是我为本文汇总的小型数据集的一部分：TextPositive?i am good✓i am bad❌this is very good✓this is not bad✓i am bad not good❌i am not at all happy❌this was good earlier✓i am not at all bad or sad right now✓计划由于这是一个分类问题，因此我们将使用“多对一” RNN。这类似于我们之前讨论的“多对多” RNN，但是它仅使用最终的 隐状态来输出y 多对一RNN每 个$x_i$将是一个向量，代表文本中的一个单词。输出$y$是一个包含两个数字的向量，一个代表正面，另一个代表负面。我们将用Softmax将这些值转换为概率，并最终确定正负。让我们开始构建我们的RNN！预处理我前面提到的数据集由两个Python字典组成：train_data = { 'good': True, 'bad': False, # ... more data } test_data = { 'this is happy': True, 'i am good': True, # ... more data }True = Positive, False = Negative我们必须进行一些预处理才能将数据转换为可用格式…

0基础入门神经网络：卷积神经网络(CNN)02
type: item
date: 2019-10-23T15:34:00+08:00
description: 原文地址在本文中，我们将深入探讨卷积神经网络（CNN）：如何训练CNN（包括梯度推导），从头实现反向传播（仅使用numpy）以及最终构建完整的训练！本文假定你对CNNs有基础了解，如果否，请参考CNN01本部分同时也要求你有多元微分的知识. 您可以根据需要跳过这些部分，但还是建议阅读它们，对写代码有用。开始我们从上一篇文章停下来的地方开始，我们正在使用CNN来解决MNIST手写数字识别问题： 来自MNIST数据集的样本图像我们（简单的）CNN由一个卷机层（Conv layer），一个最大池化层（Max Pooling layer）和一个Softmax层组成。下面是一个简单的示意图： Our (simple) CNN consisted of a Conv layer, a Max Pooling layer, and a Softmax layer. Here's that diagram of our CNN again:我们写了三个类, 分别是这三个层： Conv3x3, MaxPool, 和 Softmax. 每个类都有一个 forward() ，一种用于构建CNN前向传递的方法# Header: cnn.py conv = Conv3x3(8) # 28x28x1 -> 26x26x8 pool = MaxPool2() # 26x26x8 -> 13x13x8 softmax = Softmax(13 * 13 * 8, 10) # 13x13x8 -> 10 def forward(image, label): ''' Completes a forward pass of the CNN and calculates the accuracy and cross-entropy loss. - image is a 2d numpy array - label is a digit ''' # We transform the image from [0, 255] to [-0.5, 0.5] to make it easier # to work with. This is standard practice. out = conv.forward((image / 255) - 0.5) out = pool.forward(out) out = softmax.forward(out) # Calculate cross-entropy loss and accuracy. np.log() is the natural log. loss = -np.log(out[label]) acc = 1 if np.argmax(out) == label else 0 return out, loss, acc你可以阅读代码或 在浏览器中运行. 也可以在Github上找到它.下面是CNN的输出：MNIST CNN initialized! [Step 100] Past 100 steps: Average Loss 2.302 | Accuracy: 11% [Step 200] Past 100 steps: Average Loss 2.302 | Accuracy: 8% [Step 300] Past 100 steps: Average Loss 2.302 | Accuracy: 3% [Step 400] Past 100 steps: Average Loss 2.302 | Accuracy: 12%显然，我们希望能有10%以上的准确度……让我们训练CNN。训练概述训练神经网络通常包括两个阶段：一个前向阶段，其中输入完全通过神经网络。一个后向阶段，其中梯度被反向传播（backpropagated or backprop)，而且权重不断更新。我们将遵循这种模式来训练我们的CNN。我们还将使用两个主要特定于实现的想法：在前向阶段，每一层将缓存（cashe）任何后向阶段所需的任何数据（例如输入，中间值等）。这意味着任何后向阶段都必须在相应的前向阶段之前。在后向阶段，每一层将接收一个梯度（gradient）并且还返回一个梯度。它将获得相对于其输出的损失梯度 ($\frac{\partial L}{\partial \text{out}}$) ，并返回相对于其输入的损失梯度（$\frac{\partial L}{\partial \text{in}}$​).这两个想法将有助于保持我们训练的整洁有序。了解原因的最好方法可能是查看代码：# Feed forward out = conv.forward((image / 255) - 0.5) out = pool.forward(out) out =…

0基础入门神经网络：卷积神经网络(CNN)01
type: item
date: 2019-10-23T03:00:00+08:00
description: 原文链接在过去的几年里，关于卷积神经网络（Convolution Neural Networks，CNN）的讨论越来越多，特别是因为它彻底改变了计算机视觉领域。在本文中，我们将基于神经网络的基本背景知识，探索CNN是什么，了解它们的工作原理，并在Python中从头开始构建一个真正的CNN（仅使用numpy）。这篇文章仅假设你拥有神经网络的基本知识。我对神经网络的介绍涵盖了您需要了解的所有内容，因此您可能需要首先阅读它。为什么使用CNNCNN的经典案例是图像分类，例如查看宠物的图像并确定它是猫还是狗。那么问题来了，为什么不使用普通的神经网络？好问题原因1：图片很大如今，有关计算机视觉问题的图像通常为224x224或更大。想象一下，建立一个神经网络来处理224x224彩色图像：包括图像中的3个彩色通道（RGB），也就是说需要224 x 224 x 3 = 150528个输入特征！在这种网络中，典型的隐藏层可能有1024个节点，因此仅第一层就必须训练150,528 x 1024 = 150+百万个权重。我们的网络非常庞大，几乎无法训练。而且我们也不需要那么多的权重。我们知道像素在与其相邻的环境中最有用。图像中的对象由小的局部特征组成，例如眼睛的圆形虹膜或一张纸的方形角。第一个隐藏层中的每个节点查看每个像素是否很浪费？原因2：位置会发生变化如果你训练了一个网络来检测狗，你会希望它能够检测狗，而不管它出现在图像的什么地方。想象一下，训练一个网络，它能很好地处理一个特定的狗的图像，但是给它一个稍微改变了的图像。狗不会激活相同的神经元，所以网络的反应会完全不同！我们很快就会看到CNN如何帮助我们解决这些问题。数据集在本文中，我们将解决计算机视觉的“Hello, World!”：MNIST手写数字分类问题。很简单：给定图像，将其分类为数字。 MNIST数据集MNIST数据集中的每个图像均为28x28像素，并包含居中的灰度数字。说实话，一般的神经网络实际上可以很好地解决这个问题。您可以将每张图像视为28 x 28 = 784维向量，将其输入到784维输入层，堆叠一些隐藏层，最后得到10个节点的输出层，每个数字1个节点。但是它只会在MNIST数据集包含居中的小图像时起作用，本例中我们不会遇到上述尺寸或偏移问题。请记住，大多数现实世界中的图像分类问题并非易事。卷积什么是卷积神经网络？它是使用卷积层（又称为Conv层）的神经网络，其基于卷积的数学运算。Conv层由一组filter（卷积核）组成，您可以将其视为二维的数字矩阵。这是一个3x3卷积核示例： 我们可以输入图像和卷积核，将卷积核与输入图像卷积来生成输出图像。这包括在某些位置将卷积核覆盖在图像顶部。在卷积核中的值和图像中相应的值之间执行逐元素乘法（element-wise multiplication）。加总所有逐元素乘法的结果。和是输出图像中目标像素的输出值。在所有位置重复该过程。旁注：从技术上讲，我们（以及许多CNN）实际上在这里使用互相关而不是卷积，但是它们几乎是同一件事。我不会在这篇文章中介绍差异，因为它并不重要，但是如果您感到好奇，可以随时查找相关资料。这个四步描述有点抽象，所以让我们做一个例子。考虑一下这个微小的4x4灰度图像和3x3卷积核： 4x4图像（左）和3x3卷积核（右）图像中的数字表示像素强度，其中0为黑色，255为白色。我们将对输入图像和卷积核进行卷积以生成2x2的输出图像： 首先，让我们将卷积核覆盖在图像的左上角： 步骤1：将卷积核（右）覆盖在图像（左）的上方接下来，我们在重叠的图像值和卷积核值之间执行逐元素乘法。结果如下，从左到右，从上到下：图像值卷积核值结果0-1050000100-2080003126233-1-339000010步骤2：执行逐元素乘法。接下来，加总所有的结果，这很容易$$ 62 - 33 = \boxed{29} $$最后，我们将结果放置在输出图像的目标像素中。由于我们的卷积核覆盖在输入图像的左上角，因此我们的目标像素是输出图像的左上像素： 重复以上步骤，得到其他位置像素 它有什么用？让我们缩小一下，在更高的层次上看。将一个图像与一个卷积核进行卷积有什么用?我们可以从我们一直使用的3x3卷积核开始，它通常被称为垂直索伯滤波器 垂直索伯滤波器这是一个垂直索伯滤波器的示例： 图像与垂直索伯滤波器卷积类似地，还有一个水平索伯滤波器卷积： 水平索伯滤波器卷积 图像与水平索伯滤波器卷积看看发生了什么事？索伯滤波器是边缘检测算子（edge-detectors）。垂直索伯滤波器检测垂直边缘，而水平索伯滤波器检测水平边缘。现在可以轻松地解释输出图像：输出图像中的亮像素（值较高的像素）表明原始图像周围有很强的边缘。您能看到为什么边缘检测图像比原始图像更有用的原因吗…