以下内容有任何不理解可以翻看我之前的博客哦:吴恩达deeplearning.ai
 
文章目录
- softmax作为输出层的神经网络
 - Tensorflow的实现
 - softmax的改进实现
 - 数值舍入误差(Numerical Roundoff Errors)
 - sigmoid修改
 - 修改softmax
 
在上一篇博客中我们了解了有关softmax的原理相关内容,今天我们主要聚焦于如何修改之前的神经网络,从而搭建能够实现多分类问题的神经网络。
softmax作为输出层的神经网络

 相比之前的二分类逻辑回归神经网络,我们主要的改变是将输出层替换为了具有十个神经元的,激活函数为softmax的输出层。整个神经网络的运行流程是接收特征输入X,并且传入隐藏层,两个隐藏层的激活函数均采用的是relu函数;再传入最终输出层,最终的输出 
     
      
       
        
        
          a 
         
         
         
           [ 
          
         
           3 
          
         
           ] 
          
         
        
       
      
        a^{[3]} 
       
      
    a[3]是一个包含十个概率值的矩阵。
 我们再回顾下softmax的公式(这里仅以a1为例):
  
      
       
        
         
         
           z 
          
         
           1 
          
         
        
          = 
         
         
          
          
            w 
           
          
            1 
           
          
         
           ⃗ 
          
         
        
          ⋅ 
         
         
         
           x 
          
         
           ⃗ 
          
         
        
          + 
         
         
         
           b 
          
         
           1 
          
         
         
         
         
           a 
          
         
           1 
          
         
        
          = 
         
         
          
          
            e 
           
           
           
             z 
            
           
             1 
            
           
          
          
           
           
             e 
            
            
            
              z 
             
            
              1 
             
            
           
          
            + 
           
           
           
             e 
            
            
            
              z 
             
            
              2 
             
            
           
          
            + 
           
           
           
             e 
            
            
            
              z 
             
            
              3 
             
            
           
          
            + 
           
           
           
             e 
            
            
            
              z 
             
            
              4 
             
            
           
          
         
        
       
         z_1=\vec{w_1}\cdot\vec{x}+b_1\\ a_1=\frac{e^{z_1}}{e^{z_1}+e^{z_2}+e^{z_3}+e^{z_4}} 
        
       
     z1=w1⋅x+b1a1=ez1+ez2+ez3+ez4ez1
 此外提一个定义,softmax层有时也被叫做softmax函数。与其它的激活函数相比不同的是,softmax中 
     
      
       
        
        
          a 
         
        
          1 
         
        
       
      
        a_1 
       
      
    a1仅仅和 
     
      
       
        
        
          z 
         
        
          1 
         
        
       
      
        z_1 
       
      
    z1有关, 
     
      
       
        
        
          a 
         
        
          2 
         
        
       
      
        a_2 
       
      
    a2仅仅和 
     
      
       
        
        
          z 
         
        
          2 
         
        
       
      
        z_2 
       
      
    z2有关,而不像其它的激活函数最终的某个输出a和多个z有关。
 让我们看看如何用代码实现这个神经网络
Tensorflow的实现
第一步,构建神经网络的结构框架:
import tensorflow as tf
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
model = Sequential([
  Dense(units=25, activation='relu')
  Dense(units=15, activation='relu')
  Dense(units=10, activation='softmax')
  ])
 
第二步,定义损失函数和价值函数
from tensorflow.keras.losses import
SparseCategoricalCrossentropy
model.compile(loss=SparseCategoricalCrossentropy())
 
这里出现了一个新的函数SparseCategoricalCrossentropy(),翻译成中文叫做稀疏分类交叉熵,名字超长,甚至超过了当初的二元交叉熵。稀疏(Sparse)的意思是值只能取1~10中的一个;分类(Categorical)指的是你仍然将y分类。
 第三步,训练模型,预测代码和以前一样:
model.fit(X, Y, epochs=100)
 
以上代码是可以起作用的,符合我们之前的认知,但是还不够优化,在tensorflow中有更好的代码版本。下面我们看看如何优化softmax代码。
softmax的改进实现
数值舍入误差(Numerical Roundoff Errors)
让我先展示下在计算机设置数值的两种不同方法:
 第一种,简单粗暴法:
  
      
       
        
        
          x 
         
        
          = 
         
         
         
           2 
          
          
          
            10 
           
          
            , 
           
          
            000 
           
          
         
        
       
         x=\frac{2}{10,000} 
        
       
     x=10,0002
 第二种,加加减减法:
  
      
       
        
        
          x 
         
        
          = 
         
        
          ( 
         
        
          1 
         
        
          + 
         
         
         
           1 
          
          
          
            10 
           
          
            , 
           
          
            000 
           
          
         
        
          ) 
         
        
          − 
         
        
          ( 
         
        
          1 
         
        
          − 
         
         
         
           1 
          
          
          
            10 
           
          
            , 
           
          
            000 
           
          
         
        
          ) 
         
        
       
         x=(1+\frac{1}{10,000})-(1-\frac{1}{10,000}) 
        
       
     x=(1+10,0001)−(1−10,0001)
 虽然看上去相同,但是精确度是由差别的:
 
 我们对softmax的改进,也主要聚焦在精确度上面,让我介绍一种更加精确的方法。
sigmoid修改
在逻辑回归中,我们的公式是这样的:
  
      
       
        
        
          a 
         
        
          = 
         
        
          g 
         
        
          ( 
         
        
          z 
         
        
          ) 
         
        
          = 
         
         
         
           1 
          
          
          
            1 
           
          
            + 
           
           
           
             e 
            
           
             − 
            
           
          
            z 
           
          
         
         
        
          l 
         
        
          o 
         
        
          s 
         
        
          s 
         
        
          = 
         
        
          − 
         
        
          y 
         
        
          l 
         
        
          o 
         
        
          g 
         
        
          a 
         
        
          − 
         
        
          ( 
         
        
          1 
         
        
          − 
         
        
          y 
         
        
          ) 
         
        
          l 
         
        
          o 
         
        
          g 
         
        
          ( 
         
        
          1 
         
        
          − 
         
        
          a 
         
        
          ) 
         
        
       
         a=g(z)=\frac{1}{1+e^-z}\\ loss=-yloga-(1-y)log(1-a) 
        
       
     a=g(z)=1+e−z1loss=−yloga−(1−y)log(1−a)
 它的代码是:
model = Sequential([
  Dense(units=25, activation='relu')
  Dense(units=15, activation='relu')
  Dense(units=10, activation='sigmoid')
  ])
model.compile(loss=BinaryCrossEntropy())
 
如果我们要求tensorflow按照这个步骤,一步步算出a,然后带入到loss之中,那么结果就会如同上面的第二种方法一样产生误差,因为其进行了两步运算。但是tensorflow提供了另一种方法,大致意思就是我们先使用线性激活函数(也可以理解为没使用激活函数),最后在计算损失的时候再指定激活函数为sigmoid。如果我们使用了这个命令,这会为tensorflow提供更高的灵活性,从而可以减少误差,就如同上面的方法一;代码如下:
model = Sequential([
  Dense(units=25, activation='relu')
  Dense(units=15, activation='relu')
  Dense(units=10, activation='linear')
  ])
model.compile(loss=BinaryCrossEntropy(from_logits=True))
 
通俗点说from_ligits=True告诉了激活函数inaryCrossEntropy我没有用激活函数哦,所以你计算损失时内部记得调用下sigmoid哈。这里的logits可以理解为没有经过激活函数的z。
修改softmax
同样地,我们再看看稀疏分类交叉熵的损失函数,我就写出其中的一项:
  
      
       
        
        
          L 
         
        
          o 
         
        
          s 
         
        
          s 
         
        
          = 
         
        
          − 
         
        
          l 
         
        
          o 
         
        
          g 
         
        
          a 
          
        
          i 
         
        
          f 
         
        
          y 
         
        
          = 
         
        
          1 
         
        
       
         Loss=-loga\:ify=1 
        
       
     Loss=−logaify=1
由于在多分类问题之中,分类的选项很多,而各个选项的概率和是一定的为1,因此很多情况下正确的那个选项的概率依然很小,由于使用了log函数,在x接近于0的时候这个值会非常大,那么产生的误差也就会很大,而二分类问题由于选项仅有两个,因此这个问题不是很明显,便没在讲二分类的时候也进行这种优化。
 一样地,我们代码也可以修改为:
model = Sequential([
  Dense(units=25, activation='relu')
  Dense(units=15, activation='relu')
  Dense(units=10, activation='linear')
  ])
  from tensorflow.keras.losses import
SparseCategoricalCrossentropy
model.compile(loss=SparseCategoricalCrossentropy(from_logits=True))
 
另外需要修改的地方是,我们在预测时,model(x)不再是概率a了,而是没经过激活函数的z,因此代码在最后需要添加:
model.fit(X, Y, epochs=100)
logits = model(X)
f_x = tf.nn.softmax(logits)
 
从而再加入了softmax,出来的才是0~1之间的概率a。
 为了给读者你造成不必要的麻烦,博主的所有视频都没开仅粉丝可见,如果想要阅读我的其他博客,可以点个小小的关注哦。



















