编码实现全连接神经网络

layers.py

首先实现神经网络中仿射层、ReLU层以及组合单层神经元。

#-*- coding: utf-8 -*-
import numpy as np

def affine_forward(x, w, b):
    """
    计算神经网络当前层的前馈传播,该方法计算在全连接情况下的得分函数。
    注:如果不理解affine仿射变换,简单的理解为在全连接情况下的得分函数即可。

    输入数据x的形状为(N, d_1, ..., d_k),其中N表示数据量,(d_1, ..., d_k)表示
    每一通道的数据维度,如果是图片数据就为(长,宽,色道)。数据的总维度为
    D = d_1 * ... * d_k,因此我们需要将数据重塑成形状为(N,D)的数组再进行仿射变换。
    
    Inputs:
    - x: 输入数据,其形状为(N, d_1, ..., d_k)的numpy数组。
    - w: 权重矩阵,其形状为(D,M)的numpy数组,D表示输入数据维度,M表示输出数据维度
             可以将D看成输入的神经元个数,M看成输出神经元个数。
    - b: 偏置向量,其形状为(M,)的numpy数组。
    
    Returns 元组:
    - out: 形状为(N, M)的输出结果。
    - cache: 将输入进行缓存(x, w, b)。
    """
    out = None
    #############################################################################
    #                    任务: 实现全连接前向传播                                                         #
    #                    注:首先你需要将输入数据重塑成行。                                            #
    #############################################################################
    # 获取样本数
    N = x.shape[0]
    # 整合数据
    x_new = x.reshape(N, -1)
    # 计算仿射的得分
    out = np.dot(x_new, w)+b
    #############################################################################
    #                                                         结束编码                                                                            #
    #############################################################################
    cache = (x, w, b)
    return out, cache


def affine_backward(dout, cache):
    """
     计算仿射层的反向传播.

    Inputs:
    - dout: 形状为(N, M)的上层梯度
    - cache: 元组:
        - x: (N, d_1, ... d_k)的输入数据
        - w: 形状为(D, M)的权重矩阵

    Returns 元组:
    - dx: 输入数据x的梯度,其形状为(N, d1, ..., d_k)
    - dw: 权重矩阵w的梯度,其形状为(D,M)
    - db: 偏置项b的梯度,其形状为(M,)
    """
    x, w, b = cache
    dx, dw, db = None, None, None
    #############################################################################
    #                 任务: 实现仿射层反向传播                                                                 #
    #                 注意:你需要将x重塑成(N,D)后才能计算各梯度,                                            #
    #                 求完梯度后你需要将dx的形状与x重塑成一样                                            #
    #############################################################################
    # 计算b的梯度
    db = np.sum(dout, axis=0)
    # 将x重塑成(N, D)
    xx = x.reshape(x.shape[0], -1)
    dw = np.dot(xx.T, dout)
    dx = np.dot(dout, w.T)
    # 将dx的形状与x重塑成一样
    dx = np.reshape(dx, x.shape)
    #############################################################################
    #                                                         结束编码                                                                            #
    #############################################################################
    return dx, dw, db


def relu_forward(x):
    """
    计算rectified linear units (ReLUs)激活函数的前向传播,并保存相应缓存

    Input:
    - x: 输入数据

    Returns 元组:
    - out: 和输入数据x形状相同
    - cache: x
    """
    out = None
    #############################################################################
    #                         任务: 实现ReLU 的前向传播.                                                                        #
    #                        注意:你只需要1行代码即可完成                                                                    #
    #############################################################################
    out = np.maximum(0, x)
    #############################################################################
    #                        结束编码                                                                            #
    #############################################################################
    cache = x
    return out, cache


def relu_backward(dout, cache):
    """
    计算 rectified linear units (ReLUs)激活函数的反向传播.

    Input:
    - dout: 上层误差梯度
    - cache: 输入 x,其形状应该和dout相同

    Returns:
    - dx: x的梯度
    """
    dx, x = None, cache
    #############################################################################
    #                             任务: 实现 ReLU 反向传播.                                                                     #
    #############################################################################
    dx = dout
    dx[x<=0] = 0
    #############################################################################
    #                            结束编码                                                                             #
    #############################################################################
    return dx

def affine_relu_forward(x, w, b):
    """
     ReLU神经元前向传播

    Inputs:
    - x: 输入到 affine层的数据
    - w, b:    affine层的权重矩阵和偏置向量

    Returns 元组:
    - out:    ReLU的输出结果
    - cache: 前向传播的缓存
    """
    ######################################################################
    #                             任务: 实现 ReLU神经元前向传播.                                             #
    #                注意:你需要调用affine_forward以及relu_forward函数,                #
    #                            并将各自的缓存保存在cache中                                                     #
    ######################################################################
    a, fc_cache = affine_forward(x, w, b)
    out, relu_cache = relu_forward(a)
    cache = (fc_cache, relu_cache)
    ######################################################################
    #                                         结束编码                                                                             #
    ######################################################################
    return out, cache


def affine_relu_backward(dout, cache):
    """
     ReLU神经元的反向传播
     
    Input:
    - dout: 上层误差梯度
    - cache: affine缓存,以及relu缓存

    Returns:
    - dx: 输入数据x的梯度
    - dw: 权重矩阵w的梯度
    - db: 偏置向量b的梯度
    """
    #############################################################################
    #                             任务: 实现 ReLU神经元反向传播.                                                            #
    #############################################################################
    fc_cache, relu_cache = cache
    da = relu_backward(dout, relu_cache)
    dx, dw, db = affine_backward(da, fc_cache)
    #############################################################################
    #                                     结束编码                                                                                             #
    #############################################################################
    return dx, dw, db




def softmax_loss(x, y):
    '''
    计算Softmax损失函数

    Parameters
    ----------
    x : numpy数组
        表示训练数据.
    y : numpy数组
        表示数据类标。

    Returns
    -------
    loss : TYPE
        数据损失值
    dx : TYPE
        梯度

    '''
    probs = np.exp(x - np.max(x, axis=1, keepdims=True))
    probs /= np.sum(probs, axis=1, keepdims=True)
    # 数据量
    N = x.shape[0]
    loss = -np.sum(np.log(probs[np.arange(N), y])) / N
    dx = probs.copy()
    dx[np.arange(N), y] -= 1
    dx /= N

    return loss, dx

shallow_layer_net.py

实现浅层神经网络

#-*- coding: utf-8 -*-
import numpy as np
from .layers import *

class ShallowLayerNet(object):
    """
    浅层全连接神经网络,其中隐藏层使用ReLU作为激活函数,输出层使用softmax作为分类器
    该网络结构应该为     affine - relu -affine - softmax
    """
    
    def __init__(self, input_dim=3*32*32, hidden_dim=100, num_classes=10,
               weight_scale=1e-3, reg=0.0):
        """
        初始化网络.

        Inputs:
        - input_dim: 输入数据维度
        - hidden_dim: 隐藏层维度
        - num_classes: 分类数量
        - weight_scale: 权重范围,给予初始化权重的标准差
        - reg: L2正则化的权重衰减系数.
        """
        self.params = {}
        self.reg = reg
        ############################################################################
        #                      任务:初始化权重以及偏置项                          #
        #      权重应该服从标准差为weight_scale的高斯分布,偏置项应该初始化为0,    #
        #        所有权重矩阵和偏置向量应该存放在self.params字典中。               #
        #     第一层的权重和偏置使用键值 'W1'以及'b1',第二层使用'W2'以及'b2'      #
        ############################################################################
        self.params['W1'] = weight_scale * np.random.randn(input_dim, hidden_dim)
        self.params['b1'] = np.zeros(hidden_dim)
        self.params['W2'] = weight_scale * np.random.randn(hidden_dim, num_classes)
        self.params['b2'] = np.zeros(num_classes)
        ############################################################################
        #                           结束编码                                       #
        ############################################################################
    
    
    
    def loss(self, X, y=None):
        """
        计算数据X的损失值以及梯度.

        Inputs:
        - X: 输入数据,形状为(N, d_1, ..., d_k)的numpy数组。
        - y: 数据类标,形状为(N,)的numpy数组。

        Returns:
        如果y为 None, 表明网络处于测试阶段直接返回输出层的得分即可:
        - scores:形状为 (N, C),其中scores[i, c] 是数据 X[i] 在第c类上的得分.
        
        如果y为 not None, 表明网络处于训练阶段,返回一个元组:
        - loss:数据的损失值
        - grads: 与参数字典相同的梯度字典,键值和参数字典的键值要相同
        """  
        scores = None
        ############################################################################
        #              任务: 实现浅层网络的前向传播过程,                          #
        #                       计算各数据的分类得分                               #
        ############################################################################
        # 第1层是affine和relu的组合层
        out1, cache1 = affine_relu_forward(X, self.params['W1'], self.params['b1'])
		# 第2层是affine层
        scores, cache2 = affine_forward(out1, self.params['W2'], self.params['b2'])
        ############################################################################
        #                            结束编码                                     #
        ############################################################################

        # 如果y为 None 直接返回得分
        if y is None:
          return scores

        loss, grads = 0, {}
        ############################################################################
        #                    任务:实现浅层网络的反向传播过程,                    #
        #            将损失值存储在loss中,将各层梯度储存在grads字典中。            #
        #                           注意:别忘了还要计算权重衰减哟。               #
        ############################################################################
        # 计算最后的分类
        loss, dy = softmax_loss(scores, y)
        loss += 0.5*self.reg*(np.sum(self.params['W1']*self.params['W1'])
                   +np.sum(self.params['W2']*self.params['W2']))
        dx2, dw2, grads['b2'] = affine_backward(dy, cache2) 
        grads['W2'] = dw2 + self.reg*self.params['W2']
        dx, dw1, grads['b1'] = affine_relu_backward(dx2, cache1) 
        grads['W1'] = dw1 + self.reg*self.params['W1']
        ############################################################################
        #                             结束编码                                     #
        ############################################################################
        return loss, grads

    def train(self, X, y, X_val, y_val,
            learning_rate=1e-3, learning_rate_decay=0.95,
            reg=1e-5, num_iters=100,
            batch_size=200, verbose=False):
        """
        使用随机梯度下贱训练神经网络
        Inputs:
        - X: 训练数据
        - y: 训练类标.
        - X_val: 验证数据.
        - y_val:验证类标.
        - learning_rate: 学习率.
        - learning_rate_decay: 学习率衰减系数
        - reg: 权重衰减系数.
        - num_iters: 迭代次数.
        - batch_size: 批量大小.
        - verbose:是否在训练过程中打印结果.
        """
        num_train = X.shape[0]
        self.reg =reg
        #打印以及学习率衰减周期
        iterations_per_epoch = max(num_train / batch_size, 1)

        # 存储训练中的数据
        loss_history = []  #loss值
        train_acc_history = []  #训练精度
        val_acc_history = []  #记录精度
        best_val=-1  #记录最佳精度
        
        for it in range(num_iters):
          X_batch = None
          y_batch = None

          sample_index = np.random.choice(num_train, batch_size, replace=True)
          X_batch = X[sample_index, :]  # (batch_size,D)
          y_batch = y[sample_index]  # (1,batch_size)

          #计算损失及梯度
          loss, grads = self.loss(X_batch, y=y_batch)
          loss_history.append(loss)

          #修改权重
          self.params['W1'] += -learning_rate*grads['W1']
          self.params['W2'] += -learning_rate*grads['W2']
          self.params['b1'] += -learning_rate*grads['b1']
          self.params['b2'] += -learning_rate*grads['b2']

          if verbose and it % 100 == 0:
            print('迭代次数 %d / %d: 损失值 %f' % (it, num_iters, loss))

          if it % iterations_per_epoch == 0:
            # 测试精度
            train_acc = (self.predict(X_batch) == y_batch).mean()
            val_acc = (self.predict(X_val) == y_val).mean()
            # 记录数据
            train_acc_history.append(train_acc)
            val_acc_history.append(val_acc)
            if (best_val < val_acc):
                best_val = val_acc
            # 学习率衰减
            learning_rate *= learning_rate_decay
        # 以字典的形式返回结果
        return {
          'loss_history': loss_history,
          'train_acc_history': train_acc_history,
          'val_acc_history': val_acc_history,
          'best_val_acc':best_val
        }
    
    
    def predict(self, X):
        """
        Inputs:
        - X: 输入数据
        Returns:
        - y_pred: 预测类别
        """
        y_pred = None
        # 使用神经网络计算各类的可能性结果
        out1, cache1 = affine_relu_forward(X,self.params['W1'],self.params['b1'])
        scores, cache2 = affine_forward(out1,self.params['W2'],self.params['b2'])
        # 选择可能性最大的类别作为该样本的分类
        y_pred = np.argmax(scores, axis=1)
        return y_pred

fc_net.py

实现深层全连接网络。

#-*- coding: utf-8 -*-
import numpy as np
from .layers import *


class FullyConnectedNet(object):
    """
    深层全连接神经网络,其中隐藏层使用ReLU作为激活函数,输出层使用softmax作为分类器
    该网络结构应该为     {affine - relu}x(L -1) -affine - softmax
    """
    def __init__(self, input_dim=3*32*32, hidden_dims=[50,50], num_classes=10,
                 reg=0.0, weight_scale=1e-3):
        """
        初始化网络.

        Inputs:
        - input_dim: 输入数据维度
        - hidden_dim: 隐藏层各层维度
        - num_classes: 分类数量
        - weight_scale: 权重范围,给予初始化权重的标准差
        - reg: L2正则化的权重衰减系数.
        """
        self.reg = reg
        self.num_layers = 1 + len(hidden_dims)
        self.params = {}
        # 这里存储的是每层的神经元数量。 
        layers_dims = [input_dim] + hidden_dims + [num_classes] 
        ############################################################################
        #                    任务:初始化任意多层权重以及偏置项                    #
        #      权重应该服从标准差为weight_scale的高斯分布,偏置项应该初始化为0,    #
        #        所有权重矩阵和偏置向量应该存放在self.params字典中。               #
        #   第一层的权重和偏置使用键值 'W1'以及'b1',第n层使用'Wn'以及'bn'         #
        ############################################################################   
        for i in range(self.num_layers):
            self.params['W'+str(i+1)] = weight_scale*np.random.randn(
                layers_dims[i], layers_dims[i+1])
            self.params['b'+str(i+1)] = np.zeros((1, layers_dims[i+1]))
        ############################################################################
        #                           结束编码                                       #
        ############################################################################


    
    def loss(self, X, y=None):
        """
        计算数据X的损失值以及梯度.

        Inputs:
        - X: 输入数据,形状为(N, d_1, ..., d_k)的numpy数组。
        - y: 数据类标,形状为(N,)的numpy数组。

        Returns:
        如果y为 None, 表明网络处于测试阶段直接返回输出层的得分即可:
        - scores:形状为 (N, C),其中scores[i, c] 是数据 X[i] 在第c类上的得分.
        
        如果y为 not None, 表明网络处于训练阶段,返回一个元组:
        - loss:数据的损失值
        - grads: 与参数字典相同的梯度字典,键值和参数字典的键值要相同
        """  
        scores = None
        ############################################################################
        #              任务: 实现深层网络的前向传播过程,                          #
        #                       计算各数据的分类得分                               #
        ############################################################################
        cache_relu, outs, cache_out = {}, {}, {}
        outs[0] = X
        num_h = self.num_layers-1
        for i in range(num_h):
            outs[i+1], cache_relu[i+1] = affine_relu_forward(
                outs[i], self.params['W'+str(i+1)], self.params['b'+str(i+1)])
        scores, cache_out = affine_forward(outs[num_h], 
                                           self.params['W'+str(num_h+1)],
                                           self.params['b'+str(num_h+1)])
        ############################################################################
        #                            结束编码                                      #
        ############################################################################
        loss, grads = 0.0, {}
        ############################################################################
        #                    任务:实现深层网络的反向传播过程,                    #
        #            将损失值存储在loss中,将各层梯度储存在grads字典中。            #
        #                           注意:别忘了还要计算权重衰减哟。               #
        ############################################################################
        dout, daffine = {}, {}
        loss, dy = softmax_loss(scores, y)
        # 隐藏层数
        h = self.num_layers-1
        # 最后一层是affine层,前面的均是组合层
        for i in range(self.num_layers):
            loss += 0.5*self.reg*(np.sum(self.params['W'+str(i+1)]*self.params['W'+str(i+1)]))
            dout[h], grads['W'+str(h+1)], grads['b'+str(h+1)] = affine_backward(dy, cache_out)
            grads['W'+str(h+1)] += self.reg*self.params['W'+str(h+1)]
            for i in range(h):
                dout[h-i-1], grads['W'+str(h-i)], grads['b'+str(h-i)] = affine_relu_backward(
                    dout[h-i], cache_relu[h-i])
                grads['W'+str(h-i)] += self.reg*self.params['W'+str(h-i)]
        ############################################################################
        #                             结束编码                                     #
        ############################################################################

        return loss, grads

    def train(self, X, y, X_val, 
              y_val,learning_rate=1e-3, learning_rate_decay=0.95,
              num_iters=100,batch_size=200, verbose=False):
        """
        使用随机梯度下降训练神经网络
        Inputs:
        - X: 训练数据
        - y: 训练类标.
        - X_val: 验证数据.
        - y_val:验证类标.
        - learning_rate: 学习率.
        - learning_rate_decay: 学习率衰减系数
        - reg: 权重衰减系数.
        - num_iters: 迭代次数.
        - batch_size: 批量大小.
        - verbose:是否在训练过程中打印结果.
        """
        num_train = X.shape[0]
        iterations_per_epoch = max(num_train / batch_size, 1)

        loss_history = []
        train_acc_history = []
        val_acc_history = []
        best_val=-1
        for it in range(num_iters):

            X_batch = None
            y_batch = None
            
            sample_index = np.random.choice(num_train, batch_size, replace=True)
            X_batch = X[sample_index, :]  # (batch_size,D)
            y_batch = y[sample_index]  # (1,batch_size)

            #计算损失以及梯度
            loss, grads = self.loss(X_batch, y=y_batch)
            loss_history.append(loss)
            
            #修改权重
            ############################################################################
            #                    任务:修改深层网络的权重                              #
            ############################################################################
            for i,j in self.params.items():
                self.params[i] += -learning_rate*grads[i]
            ############################################################################
            #                              结束编码                                    #
            ############################################################################
            if verbose and it % 100 == 0:
                print('iteration %d / %d: loss %f' % (it, num_iters, loss))

            if it % iterations_per_epoch == 0:
                # 检验精度
                train_acc = (self.predict(X) == y).mean()
                val_acc = (self.predict(X_val) == y_val).mean()
                # 记录数据
                train_acc_history.append(train_acc)
                val_acc_history.append(val_acc)
                if (best_val < val_acc):
                    best_val = val_acc
                # 学习率衰减
                learning_rate *= learning_rate_decay
        # 以字典的形式返回结果
        return {
          'loss_history': loss_history,
          'train_acc_history': train_acc_history,
          'val_acc_history': val_acc_history,
          'best_val_acc':best_val
        }
    
    def predict(self, X):
        """
        Inputs:
        - X: 输入数据
        Returns:
        - y_pred: 预测类别
        """
        y_pred = None
        ###########################################################################
        #                   任务: 执行深层网络的前向传播,                       #
        #                  然后使用输出层得分函数预测数据类标                     #
        ###########################################################################
        outs = {}
        outs[0] = X
        num_h = self.num_layers-1
        for i in range(num_h):
            outs[i+1], _ =affine_relu_forward(outs[i], self.params['W'+str(i+1)],
                                              self.params['b'+str(i+1)])
        scores, _ = affine_forward(outs[num_h], self.params['W'+str(num_h+1)], 
                                   self.params['b'+str(num_h+1)])
        y_pred = np.argmax(scores, axis=1)
        ###########################################################################
        #                             结束编码                                    #
        ###########################################################################
        return y_pred

上一篇:Echarts立体地图加3D柱图可点击可高亮选中的开发


下一篇:java请求登录接口代码示例