Softmax分类和两层神经网络以及反向传播的代码推导

2023-11-13

发现草稿箱里还有一篇很早之前的学习笔记,希望可以帮助到有需要的童鞋~

目录

Softmax分类器

反向传播

数据构建以及网络训练

交叉验证参数优化 


       原来都是用的c++学习的传统图像分割算法。主要学习聚类分割、水平集、图割,欢迎一起讨论学习。

       刚刚开始学习cs231n的课程,正好学习python,也做些实战加深对模型的理解。

       课程链接

       1、这是自己的学习笔记,会参考别人的内容,如有侵权请联系删除。

       2、代码参考WILL 、杜克,但是有了很多自己的学习注释

       3、有些原理性的内容不会讲解,但是会放上我觉得讲的不错的博客链接

       4、由于之前没怎么用过numpy,也对python不熟,所以也是一个python和numpy模块的学习笔记

       本章前言:softmax本来应该单独成为一节,但是由于内容和前面的章节高度重复,神经网络中又使用了softmax输出,考虑之后将softmax的内容和neural network放到一起。阅读本章内容需要有神经网络的基本知识。本章重点:反向传播

       在jupyter中写的代码,要import需要下载成为.py文件,import之后如果.py文件中的内容有了修改需要重新打开jupyter,很麻烦,现在在import之后加上以下代码,更改.py文件后就不需要重新打开jupyter了。

#自动加载外部模块
%reload_ext autoreload
%autoreload 2

Softmax分类器

       softmax分类器可以看作是在svm得分的基础上,利用公式将得分转化为相对应的概率。

给出softmax的代价函数的代码实现,同样分为朴素版和向量版 

import numpy as np
from random import shuffle

def softmax_loss_naive(W, X, y, reg):
    loss = 0.0
    num_classes = W.shape[1]
    num_train = X.shape[0]
    for i in range(num_train):
        f_i = X[i].dot(W)
        f_i = f_i - np.max(f_i)  #减小数值,增强稳定性
        sum_j = np.sum(np.exp(f_i))
        p = lambda k:np.exp(f_i[k])/sum_j
        loss += -np.log(p(y[i]))       #只要计算正确的那一类的损失
        
        #计算梯度
        for k in range(num_classes):
            p_k = p(k)
            dW[:,k]+=(p_k-(k==y[i]))*X[i]
    loss / = num_train
    loss+= 0.5 * reg * np.sum(W*W)
    dW /= num_train
    dW += reg*W
    
    return loss,dW

def softmax_loss_vectorized(W,X,y,reg):
    num_train = X.shape[0]
    f = X.dot(W)
    f -= np.max(f,axis =1,keepdims = True)
    sum_f = np.sum(np.exp(f),axis=1,keepdims=True)
    p = np.exp(f)/sum_f
    
    loss = np.sum(-np.log(p[np.arange(num_train),y]))  #查找每一行正确分类的元素
    
    ind = np.zeros_like(p)
    ind[np.arange(num_train),y]=1       #正确分类需要用概率减一,创建0矩阵,正确分类部分为1
    dW = X.T.dot(p-ind)
    
    loss / = num_train
    loss+= 0.5 * reg * np.sum(W*W)
    dW /= num_train
    dW += reg*W
    
    return loss,dW

反向传播

       上面代码中计算权重矩阵梯度时用到了反向传播中的链式求导法则的思想。关于反向传播的理解,这里给出两个链接帮助理解:深度学习——对于反向传播的理解(举例验证)        

       CS231n课程笔记翻译:反向传播笔记

       读完这两篇对反向传播中的链式求导有了基础了解,下面就是一个二层神经网络的反向传播的推导过程(字丑),其中softmax部分的推导参考课程。

       参考上述推导过程,下面给出两层神经网络的实现方式:

import numpy as np

class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size,std=1e-4):
        self.params = {}
        #初始化权重矩阵
        self.params['W1'] = std * np.random.randn(input_size,hidden_size)   #W1.shape = (输入层特征数,隐藏层特征数)
        self.params['b1'] = np.zeros(hidden_size)                           #b1.shape = (1, 隐藏层特征数)
        self.params['W2'] = std * np.random.randn(hidden_size,output_size)  #W2.shape = (输入层特征数,隐藏层特征数)
        self.params['b2'] = np.zeros(output_size)
        
    def loss(self,X,y = None,reg = 0.0):
        W1, b1 = self.params['W1'],self.params['b1']
        W2, b2 = self.params['W2'],self.params['b2']
        N,D = X.shape     #N样本数num,D特征维度dimension
        
        scores = None     #得分
        
        h_output = np.maximum(0,X.dot(W1) + b1)   #隐藏层输出(N,H),Relu激活, X是以行来存储  np.maximum比较两组数据的最大值
        scores = h_output.dot(W2) + b2            #输出层(未激活)(N,C)
        
        #如果没有输入y,则直接输出得分
        if y is None:
            return scores
        
        loss = None
        
        #softmax中包含exp,值会比较大,为减小数值采取归一化操作
        shift_scores = scores - np.max(scores,axis = 1).reshape((-1,1))   #归一化,计算每一行的最大值,然后把所有的score减去该max,这是和图像归一化中每个特征减去特诊的max不一样的
        softmax_output = np.exp(shift_scores)/np.sum(np.exp(shift_scores),axis = 1).reshape(-1,1)   #softmax公式
        loss = -np.sum(np.log(softmax_output[range(N), list(y)]))         #计算代价(前面的负号是公式)
        loss/= N                                                          #计算均值
        loss += 0.5*reg*(np.sum(W1*W1)+np.sum(W2*W2))                     #正则,需要将每一层的权值加起来
        
        #输出层计算梯度,参考softmax梯度计算
        grads= {}
        dscores= softmax_output
        dscores[range(N), list(y)] -= 1
        dscores /= N
        grads['W2'] = h_output.T.dot(dscores) + reg*W2
        grads['b2'] = np.sum(dscores,axis = 0)
        
        #隐藏层梯度计算
        dh = dscores.dot(W2.T)
        dh_ReLu = (h_output>0)*dh
        grads['W1'] = X.T.dot(dh_ReLu) + reg*W1
        grads['b1'] = np.sum(dh_ReLu,axis=0)
        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 = 1000,batch_size=200,verbose=False):
        num_train = X.shape[0]
        iterations_per_epoch = max(num_train/batch_size,1)  #每一轮的迭代数目,1个epoch等于使用训练集中的全部样本训练一次
        loss_history =[]
        train_acc_history = []
        val_acc_history = []
        
        for it in range(num_iters):
            X_bacth = None
            y_batch = None
            
            idx = np.random.choice(num_train,batch_size,replace = True)
            X_bacth = X[idx]
            y_batch = y[idx]
            loss,grads = self.loss(X_bacth,y=y_batch,reg = reg)
            loss_history.append(loss)
            
            #参数更新
            self.params['W2'] += -learning_rate*grads['W2']
            self.params['b2'] += -learning_rate*grads['b2']
            self.params['W1'] += -learning_rate*grads['W1']
            self.params['b1'] += -learning_rate*grads['b1']
            
            if verbose and it %100 ==0:
                print('iteration %d / %d : loss %f '(it,num_iters,loss))
            
            #每次epoch说明遍历1次训练集,记录精度,并且更改学习率
            if it % iterations_per_epoch == 0:
                train_acc = (self.predict(X_bacth)==y_batch).mean()
                val_acc = np.mean(self.predict(X_val)==y_val)
                train_acc_history.append(train_acc)
                val_acc_history.append(val_acc)
                
                learning_rate*= learning_rate_decay
            
        return {
            'loss_history':loss_history,
            'train_acc_history':train_acc_history,
            'val_acc_history':val_acc_history
        }
    
    def predict(self,X):
        y_pred = None
        h = np.maximum(0,X.dot(self.params['W1'])+self.params['b1'])
        scores = h.dot(self.params['W2'])+self.params['b2']
        y_pred = np.argmax(scores,axis=1)    #取得概率最大的位置
        return y_pred

数据构建以及网络训练

       将之前的数据构建整合成一个方法,注意这边的归一化操作是将每个特征减去对应的特征点最大值,这和softmax中一组得分减取改组得分的最大值不一样。

def get_cifar_data(num_training =49000,num_validation=1000,num_test=1000):
    X_train,y_train,X_test,y_test = load_cifar10('cifar-10-batches-py')
    #验证集
    mask = range(num_training, num_training+num_validation)     #先取验证集,大小为最后的1000条数据
    x_val = X_train[mask]
    y_val = y_train[mask]
    #训练集
    mask = range(num_training)
    x_train = X_train[0:num_training,:,:,:]
    y_train = y_train[mask]
    #测试集
    mask = range(num_test)
    x_test = X_test[mask]
    y_test = y_test[mask]
    
    mean_image = np.mean(x_train, axis=0)
    #归一化操作,将所有的特征都减去对应的均值
    x_train -= mean_image
    x_val -= mean_image
    x_test -= mean_image

    x_train = np.reshape(x_train,(x_train.shape[0],-1))
    x_val = np.reshape(x_val,(x_val.shape[0],-1))
    x_test = np.reshape(x_test,(x_test.shape[0],-1))
    return x_train,y_train,x_val,y_val,x_test,y_test

数据构建测试 

X_train,y_train,X_val,y_val,X_test,y_test = get_cifar_data()
print('Train data shape: ', X_train.shape)
print('Train labels shape: ', y_train.shape)
print("validation data shape: ", X_val.shape)
print('validation labels shape: ', y_val.shape)
print('test data shape: ', X_test.shape)
print('test labels shape: ',y_test.shape)

"""
X_train,y_train,X_val,y_val,X_test,y_test = get_cifar_data()
print('Train data shape: ', X_train.shape)
print('Train labels shape: ', y_train.shape)
print("validation data shape: ", X_val.shape)
print('validation labels shape: ', y_val.shape)
print('test data shape: ', X_test.shape)
print('test labels shape: ',y_test.shape)
"""

 训练

input_size = 32*32*3
hidden_size = 50
num_class = 10
net = TwoLayerNet(input_size,hidden_size,num_class)
stats = net.train(X_train,y_train,X_val,y_val,learning_rate = 1e-3,learning_rate_decay=0.95,reg=1e-5,num_iters = 1000,batch_size=200,verbose=True)
val_acc = (net.predict(X_val)==y_val).mean()
print('validation accuracy:',val_acc)

"""
iteration 0 / 1000 : loss 2.302589 
iteration 100 / 1000 : loss 1.907440 
iteration 200 / 1000 : loss 1.798388 
iteration 300 / 1000 : loss 1.721173 
iteration 400 / 1000 : loss 1.639906 
iteration 500 / 1000 : loss 1.691722 
iteration 600 / 1000 : loss 1.623998 
iteration 700 / 1000 : loss 1.493039 
iteration 800 / 1000 : loss 1.543409 
iteration 900 / 1000 : loss 1.500300 
validation accuracy: 0.48
"""

#loss和accuracy的可视化
plt.subplot(211)
plt.plot(stats['loss_history'])
plt.title('loss history')
plt.xlabel('iteration')
plt.ylabel('loss')

plt.subplot(212)
plt.plot(stats['train_acc_history'],label='train')
plt.plot(stats['val_acc_history'],label = 'val')
plt.title('classfication accuracy history')
plt.xlabel('epoch')
plt.ylabel('classfication accuracy')
plt.show()


权重矩阵的可视化 

from visualize_grid import *
def show_net_weights(net):
    W1 = net.params['W1']
    W1 = W1.reshape(32,32,3,-1).transpose(3,0,1,2)
    plt.imshow(visualize_grid(W1,padding=3).astype('uint8'))
    plt.gca().axis('off')
    plt.show()
show_net_weights(net)


交叉验证参数优化 

#交叉验证
input_size=32*32*3
num_class = 10
hidden_size=[75,100,125]
results={}
best_val_acc= 0
best_net=None
learning_rates = np.array([0.7,0.8,0.9])*1e-3
regulation_strengths=[0.75,1.0,1.25]
print('run')
for hs in hidden_size:
    for lr in learning_rates:
        for reg in regulation_strengths:
            net = TwoLayerNet(input_size,hs,num_class)
            
            stats=net.train(X_train,y_train,X_val,y_val,learning_rate = lr,learning_rate_decay=0.95,reg=reg,num_iters = 1000,batch_size=200,verbose=False)
            val_acc=np.mean(net.predict(X_val)==y_val)
            if val_acc > best_val_acc:
                best_val_acc = val_acc
                best_net = net
            results[(hs,lr,reg)]=val_acc
print('finish')

for hs,lr,reg in sorted(results):
    val_acc = results
    print('hs %d lr %e reg %e val accuract: %f' % (hs,lr,reg,val_acc))
print('best validation accuracy achived during cross_validation:%f' %best_val_acc)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Softmax分类和两层神经网络以及反向传播的代码推导 的相关文章

  • linux系统中解决docker: command not found

    新申请了一台阿里云的服务器 打算在上边部署一个容器服务 竟然发现机器上连docker都没安装 如果是mac OS系统 可以参考文章 mac系统中解决docker command not found 解决 针对这个问题 今天特意记录了一下 我
  • 网上总结的字节跳动前端面试题

    1 jQuery与Vue的区别是什么 Vue vue是一个兴起的前端js库 是一个精简的MVVM 从技术角度讲 Vue js 专注于 MVVM 模型的 ViewModel 层 它通过双向数据绑定把 View 层和 Model 层连接了起来
  • Python爬虫常见异常及解决办法

    文章目录 1 selenium common exceptions WebDriverException Message unknown error cannot find Chrome binary 方法一 配置参数 方法二 修改源文件

随机推荐

  • mysql学习-mysql数据类型学习01

    数据类型概览 数值类型 整数类型包括 TINYINT SMALLINT MEDIUMINT INT BIGINT 浮点数类型包括 FLOAT 和 DOUBLE 定点数类型为 DECIMAL tinyint smallint mediumin
  • 【MySQL】MYSQL内核:INNODB存储引擎 卷1pdf——百度网盘下载

    百度网盘地址 https pan baidu com s 1p4CsmBhYzrIawwUznmByYw 资源来之不易 需要获取密码 请关注公众号 全栈船长 并回复数字 0002
  • 前端开发:JS中截取字符串的用法总结,高级Android程序员必会

    var a 0123456789 a substring 5 2 4 start 和 stop 有字符串 但是最后的输出结果是 234 a substring 5 hh start 和 stop 有字符串 但是最后的输出结果是 234 二
  • 计算机在汽车设计方面的应用属于计算机的,计算机技术辅助设计在汽车设计中的应用.pdf...

    82 车辆与动力工程 Vehicles and Power Engineering 2017 年 2 月 计算机技术辅助设计在汽车设计中的应用 温 欣 汪 家宇 杨 海 南 沈 阳理工 大学 辽 宁 沈 阳 110159 摘 要 随着社会经
  • keil软件调试(Debug)仿真教程(软件调试和硬件调试的区别)及常用调试按键详解

    文章目录 前言 一 什么是软件调试 Debug 有什么用 二 keil Debug常用按钮 总结 前言 单片机的调试分为两种 一种是使用软件模拟调试 第二种是硬件调试 两种调试方式各有不同 软件模拟调试有误差 而硬件调试 借用仿真器调试是嵌
  • 新斗罗大陆手游服务器维护,《新斗罗大陆》新ss魂师天青龙牛天修复公告

    亲爱的魂师大人 新SS魂师天青龙牛天首发后 小舞收到了大量意见反馈 部分魂师大人认为牛天战斗结果异常 过高的伤害与其魂师定位不符 我们在接收到反馈的第一时间 进行了紧急核查 随后 我们发现该问题是由牛天的技能 龙魂觉醒 导致 当牛天施展该技
  • AQS原理解析及源码分析

    目录 1 介绍下AQS几个重要的组件 2 内部成员变量state 3 同步队列NODE 4 等待队列 condition AbstractQueuedSynchronizer又称为队列同步器 后面简称AQS AQS的核心思想是 如果被请求的
  • 对比梯度下降和正规方程解性能

    现在用导数的方式模拟线性回归中的梯度下降法 首先再来回顾一下梯度下降法的基础 梯度下降法不是一个机器学习算法 而是一个搜索算法 梯度下降法用在监督学习中 梯度下降法的过程 对比模型输出值和样本值的差异不断调整本省权重 直到最后模型输出值和样
  • Leetcode题解——26.树的子结构

    题目地址 剑指 Offer 26 树的子结构 力扣 LeetCode 目录 一 解题思路 一 大体思路 二 Search函数 三 Judge函数 二 代码实现 三 拓展思考 一 解题思路 一 大体思路 对于二叉树类的题目 一般会使用递归或层
  • YOLOv5 tensorRT C++代码详解之engine的读取

    在tensorRT中 engine模型是对yolov5序列化后的结果 在推理的时候需要进行反序列化才能进行推理 那么第一步就是读取engine文件 ifstream介绍 engine文件的读取需要用到ifstream 需要导入头文件 inc
  • SpringBoot最简单好用的导出导入功能,拿来即用

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 拿来吧你 一 接口说明 二 依赖 三 导出工具类 四 导入工具类 五 实体类的改造 BaseEntity java 六 控制层使用 七 效果 数据库表 1 下载模板
  • C++中三种产生随机数的方法

    第一种方法 使用时间做为生成随机数的种子 include
  • 190705 安卓-对抗AndResGuard的重打包

    换了一个apk实验后 apktool b f p xxx也不行 仍然报资源错误 看了一下可能是鹅厂出的AndResGuard工具 会将资源文件夹 Res xxx重命名为 r x类的目录 导致资源解析出错 针对这个混淆有shakaApktoo
  • volatile 的理解

    文章目录 前言 通过一系列的问题 了解volatile 总结 前言 在面试的时候 经常会遇到多线程的问题 然后面试官会提到 你是怎么做到线程安全的 然后就会涉及到关键字volatile 这个是在面试过程中高频率出现的 所以还是有必要对它进行
  • 岭回归(Ridge Regression)及实现

    岭回归 Ridge Regression 及实现 https blog csdn net google19890102 article details 27228279 一 一般线性回归遇到的问题 在处理复杂的数据的回归问题时 普通的线性回
  • linux驱动调试--段错误之栈信息分析

    转自 http blog chinaunix net xmlrpc php r blog article uid 29401328 id 4923529 接着上一篇来分析一下Oops的栈 s3c2440平台 关于调试源码和整个Oops信息请
  • LeetCode-1318. Minimum Flips to Make a OR b Equal to c

    Given 3 positives numbers a b and c Return the minimum flips required in some bits of a and b to make a OR b c bitwise O
  • 图像清晰度评价指标(Python)

    最近在毕业设计中涉及了有关增强图像清晰度的实验 需要一些指标来进行实验结果的评估 刚好网上有个总结的非常好的博客 见参考文献 1 但没有实现方法 因此 我将在我的博客中用Python实现 评估方法实现 所有函数的具体说明都在参考文献 1 里
  • QMap和QHash类

    QMap和QHash具有非常相似的功能 它们的差别仅在于 1 QHash具有比QMap更快的查找速度 2 QHash以任意的顺序存储数据项 而QMap总是按照键 key的顺序存储数据 3 QHash的键类型 Key必须提供operator
  • Softmax分类和两层神经网络以及反向传播的代码推导

    发现草稿箱里还有一篇很早之前的学习笔记 希望可以帮助到有需要的童鞋 目录 序 Softmax分类器 反向传播 数据构建以及网络训练 交叉验证参数优化 序 原来都是用的c 学习的传统图像分割算法 主要学习聚类分割 水平集 图割 欢迎一起讨论学