Navigation

    Gpushare.com

    • Register
    • Login
    • Search
    • Popular
    • Categories
    • Recent
    • Tags

    “Salute!”从零开始softmax的实现-tensorflow

    CV领域
    2
    2
    106
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • 153****2211
      153****2211 last edited by

      1.softmax的数学公式

      1.1softmax的公式

      在这里插入图片描述

      1.2softmax的损失函数

      softmax使用是损失函数是交叉熵(cross entropy),数学公式表现如下
      在这里插入图片描述
      也就是说,交叉熵只关心对正确类别的预测概率,因为只要其值足够大,就可以确保分类结果正确。当然,遇到一个样本有多个标签时,例如图像里含有不止一个物体时,我们并不能做这一步简化。但即便对于这种情况,交叉熵同样只关心对图像中出现的物体类别的预测概率。

      假设训练数据集的样本数为nn,交叉熵损失函数定义为
      在这里插入图片描述

      1.3小结

      总而言之,softmax是将最后一层所得到的结果,进行转换成总和为1的概率问题。

      2.softmax的python代码

      2.1 导入库

      import tensorflow as tf
      import numpy as np
      print(tf.__version__)
      

      ↑基本模块tensorflow跟numpy的导入

      from tensorflow.keras.datasets import fashion_mnist
      
      batch_size=256
      (x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()
      x_train = tf.cast(x_train, tf.float32) / 255 #在进行矩阵相乘时需要float型,故强制类型转换为float型
      x_test = tf.cast(x_test,tf.float32) / 255 #在进行矩阵相乘时需要float型,故强制类型转换为float型
      train_iter = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(batch_size)
      test_iter = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(batch_size)
      
      

      ↑这里很好理解就是定义train 跟 test 的数据来源与类型

      num_inputs = 784
      num_outputs = 10
      W = tf.Variable(tf.random.normal(shape=(num_inputs, num_outputs), mean=0, stddev=0.01, dtype=tf.float32))
      b = tf.Variable(tf.zeros(num_outputs, dtype=tf.float32))
      

      ↑初始化模块参数,因为minst-fashion的图像都是28x28的所以作为为全连接层,就是784个节点,output就是指最后输出的10个类别的参数。

      def softmax(logits, axis=-1):
          return tf.exp(logits)/tf.reduce_sum(tf.exp(logits), axis, keepdims=True)
      
      

      ↑定义softmax的运算:为了更好理解代码就将上面公式拿过来
      在这里插入图片描述
      tf.exp(logits):是给logic进行exp运算就是log
      tf.reduce_sum()在这里插入图片描述
      在这里插入图片描述
      我们可以得知就是进行上面式子的操作

      def net(X):
          logits = tf.matmul(tf.reshape(X, shape=(-1, W.shape[0])), W) + b
          return softmax(logits)
      
      

      ↑定义模型:tf.reshape 是将X,转换成W的行数,前面的-1表示函数自动计算列数。这一步是为了消除x与w矩阵不匹配的问题。
      shape[0] = = >行数

      shape[1] = =>列数
      而tf.matmul函数就是进行X*W的矩阵运算。

      def cross_entropy(y_hat, y):
          y = tf.cast(tf.reshape(y, shape=[-1, 1]),dtype=tf.int32)
          y = tf.one_hot(y, depth=y_hat.shape[-1])
          y = tf.cast(tf.reshape(y, shape=[-1, y_hat.shape[-1]]),dtype=tf.int32)
          return -tf.math.log(tf.boolean_mask(y_hat, y)+1e-8)
      
      

      ↑定义损失函数:
      假设y=[0,2] 一行两列 y_hat=[[0.1,0.3,0.6] [0.3,0.2,0.5]] 两行三列
      第一步
      先进行数据类型的转换,转换成int类型,并且用reshape(-1,1)函数将y变成N行一列的矩阵。 y=[[0],[2]]两行一列
      第二步
      进行one_hot,首先进行depth的计算,y_hat.shape[-1]指定是列数就是3所以depth=3。式子就变成了y=th.one_hot(y,3)
      而 one_hot是返回一个张量,这里如果不好理解可以查阅该函数的解释。这里就不多介绍了
      所以y就变成一个2x1x3的矩阵,并进行了热编码为[[1,0,0][0,0,1]],==这是二维的向量==
      第三步
      shape=[-1, y_hat.shape[-1]])中y_hat.shape[-1]为3,所以最后将y变成n行3列,用我假设的矩阵的话y就是([1,0,0][0,0,1])==这是一维的向量==
      第四步
      进行计算tf.boolean_mask(y_hat, y),这里可以理解为矩阵运算,得到的结果就是([0.1][0.5]),然后再+1e-8,在进行log计算

      def accuracy(y_hat, y):
          return np.mean((tf.argmax(y_hat, axis=1) == y))
      
      

      ↑这里是进行数据预测,最后的结果与实际结果是否相吻合。简而言之那上述举得例子。y=[0,2] 一行两列 y_hat=[[0.1,0.3,0.6] [0.3,0.2,0.5]] 两行三列
      那么得到的结果就是0.5的准确率应为y_hat 的最大之因该为[2,2]。

      # 描述,对于tensorflow2中,比较的双方必须类型都是int型,所以要将输出和标签都转为int型
      def evaluate_accuracy(data_iter, net):
          acc_sum, n = 0.0, 0
          for _, (X, y) in enumerate(data_iter):
              y = tf.cast(y,dtype=tf.int64)
              acc_sum += np.sum(tf.cast(tf.argmax(net(X), axis=1), dtype=tf.int64) == y)
              n += y.shape[0]
          return acc_sum / n
      
      

      ↑这里是我们可以评价模型net在数据集data_iter上的准确率。

      #完整的训练数据集
      num_epochs, lr = 5, 0.1
      def train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params=None, lr=None, trainer=None):
          for epoch in range(num_epochs):
              train_l_sum, train_acc_sum, n = 0.0, 0.0, 0
              for X, y in train_iter:
                  with tf.GradientTape() as tape:
                      y_hat = net(X)
                      l = tf.reduce_sum(loss(y_hat, y))
                  grads = tape.gradient(l, params)
                  if trainer is None:
                      # 如果没有传入优化器,则使用原先编写的小批量随机梯度下降
                      for i, param in enumerate(params):
                          param.assign_sub(lr * grads[i] / batch_size)
                  else:
                      # tf.keras.optimizers.SGD 直接使用是随机梯度下降 theta(t+1) = theta(t) - learning_rate * gradient
                      # 这里使用批量梯度下降,需要对梯度除以 batch_size, 对应原书代码的 trainer.step(batch_size)
                      trainer.apply_gradients(zip([grad / batch_size for grad in grads], params))  
      
                  y = tf.cast(y, dtype=tf.float32)
                  train_l_sum += l.numpy()
                  train_acc_sum += tf.reduce_sum(tf.cast(tf.argmax(y_hat, axis=1) == tf.cast(y, dtype=tf.int64), dtype=tf.int64)).numpy()
                  n += y.shape[0]
              test_acc = evaluate_accuracy(test_iter, net)
              print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'% (epoch + 1, train_l_sum / n, train_acc_sum / n, test_acc))
      
      trainer = tf.keras.optimizers.SGD(lr)
      train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, batch_size, [W, b], lr)
      
      

      ↑

      #预测结果
      import matplotlib.pyplot as plt
      X, y = iter(test_iter).next()
      
      def get_fashion_mnist_labels(labels):
          text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat', 'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
          return [text_labels[int(i)] for i in labels]
      
      def show_fashion_mnist(images, labels):
          # 这⾥的_表示我们忽略(不使⽤)的变量
          _, figs = plt.subplots(1, len(images), figsize=(12, 12)) # 这里注意subplot 和subplots 的区别
          for f, img, lbl in zip(figs, images, labels):
              f.imshow(tf.reshape(img, shape=(28, 28)).numpy())
              f.set_title(lbl)
              f.axes.get_xaxis().set_visible(False)
              f.axes.get_yaxis().set_visible(False)
          plt.show()
      
      true_labels = get_fashion_mnist_labels(y.numpy())
      pred_labels = get_fashion_mnist_labels(tf.argmax(net(X), axis=1).numpy())
      titles = [true + '\n' + pred for true, pred in zip(true_labels, pred_labels)]
      
      show_fashion_mnist(X[0:9], titles[0:9])
      
      

      ↑

      3.softmax的keras代码

      import tensorflow as tf
      from tensorflow import keras
      fashion_mnist = keras.datasets.fashion_mnist
      (x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()
      x_train = x_train / 255.0
      x_test = x_test / 255.0
      model = keras.Sequential([
          keras.layers.Flatten(input_shape=(28, 28)),
          keras.layers.Dense(10, activation=tf.nn.softmax)
      ])
      model.compile(optimizer=tf.keras.optimizers.SGD(0.1),
                    loss = 'sparse_categorical_crossentropy',
                    metrics=['accuracy'])
      
      model.fit(x_train,y_train,epochs=5,batch_size=256)
      
      test_loss, test_acc = model.evaluate(x_test, y_test)
      print('Test Acc:',test_acc)
      

      这里代码就不进行过多的叙述,用kreas这种高度集合的框架确实方便。但是这种对日后代码具体调试是极为不利的。
      这是自己很早之前写的,copy过来偷个懒

      1 1 Reply Last reply Reply Quote 8
      • 1
        130****1521 @153****2211 last edited by

        @153-2211 还是有点不够清楚😊

        1 Reply Last reply Reply Quote 2
        • First post
          Last post