1. 程式人生 > >keras中to_categorical函式解析

keras中to_categorical函式解析

1.to_categorical的功能

簡單來說,to_categorical就是將類別向量轉換為二進位制(只有0和1)的矩陣型別表示。其表現為將原有的類別向量轉換為獨熱編碼的形式。先上程式碼看一下效果:

from keras.utils.np_utils import *
#類別向量定義
b = [0,1,2,3,4,5,6,7,8]
#呼叫to_categorical將b按照9個類別來進行轉換
b = to_categorical(b, 9)
print(b)

執行結果如下:
[[1. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 1. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 1. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 1. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 1. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 1. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 1.]]

to_categorical最為keras中提供的一個工具方法,從以上程式碼執行可以看出,將原來類別向量中的每個值都轉換為矩陣裡的一個行向量,從左到右依次是0,1,2,...8個類別。2表示為[0. 0. 1. 0. 0. 0. 0. 0. 0.],只有第3個為1,作為有效位,其餘全部為0。

2.one_hot encoding(獨熱編碼)介紹

獨熱編碼又稱為一位有效位編碼,上邊程式碼例子中其實就是將類別向量轉換為獨熱編碼的類別矩陣。也就是如下轉換:

     0  1  2  3  4  5  6  7  8
0=> [1. 0. 0. 0. 0. 0. 0. 0. 0.]
1=> [0. 1. 0. 0. 0. 0. 0. 0. 0.]
2=> [0. 0. 1. 0. 0. 0. 0. 0. 0.]
3=> [0. 0. 0. 1. 0. 0. 0. 0. 0.]
4=> [0. 0. 0. 0. 1. 0. 0. 0. 0.]
5=> [0. 0. 0. 0. 0. 1. 0. 0. 0.]
6=> [0. 0. 0. 0. 0. 0. 1. 0. 0.]
7=> [0. 0. 0. 0. 0. 0. 0. 1. 0.]
8=> [0. 0. 0. 0. 0. 0. 0. 0. 1.]

那麼一道思考題來了,讓你自己編碼實現類別向量向獨熱編碼的轉換,該怎樣實現呢?

以下是我自己粗淺寫的一個小例子,僅供參考:

def convert_to_one_hot(labels, num_classes):
    #計算向量有多少行
    num_labels = len(labels)
    #生成值全為0的獨熱編碼的矩陣
    labels_one_hot = np.zeros((num_labels, num_classes))
    #計算向量中每個類別值在最終生成的矩陣“壓扁”後的向量裡的位置
    index_offset = np.arange(num_labels) * num_classes
    #遍歷矩陣,為每個類別的位置填充1
    labels_one_hot.flat[index_offset + labels] = 1
    return labels_one_hot
#進行測試
b = [2, 4, 6, 8, 6, 2, 3, 7]
print(convert_to_one_hot(b,9))

測試結果:
[[0. 0. 1. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 1. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 1. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 1.]
 [0. 0. 0. 0. 0. 0. 1. 0. 0.]
 [0. 0. 1. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 1. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 1. 0.]]

3.原始碼解析

to_categorical在keras的utils/np_utils.py中,原始碼如下:

def to_categorical(y, num_classes=None, dtype='float32'):
    """Converts a class vector (integers) to binary class matrix.
    E.g. for use with categorical_crossentropy.
    # Arguments
        y: class vector to be converted into a matrix
            (integers from 0 to num_classes).
        num_classes: total number of classes.
        dtype: The data type expected by the input, as a string
            (`float32`, `float64`, `int32`...)
    # Returns
        A binary matrix representation of the input. The classes axis
        is placed last.
    # Example
    ```python
    # Consider an array of 5 labels out of a set of 3 classes {0, 1, 2}:
    > labels
    array([0, 2, 1, 2, 0])
    # `to_categorical` converts this into a matrix with as many
    # columns as there are classes. The number of rows
    # stays the same.
    > to_categorical(labels)
    array([[ 1.,  0.,  0.],
           [ 0.,  0.,  1.],
           [ 0.,  1.,  0.],
           [ 0.,  0.,  1.],
           [ 1.,  0.,  0.]], dtype=float32)
    ```
    """
    #將輸入y向量轉換為陣列
    y = np.array(y, dtype='int')
    #獲取陣列的行列大小
    input_shape = y.shape
    if input_shape and input_shape[-1] == 1 and len(input_shape) > 1:
        input_shape = tuple(input_shape[:-1])
    #y變為1維陣列
    y = y.ravel()
    #如果使用者沒有輸入分類個數,則自行計算分類個數
    if not num_classes:
        num_classes = np.max(y) + 1
    n = y.shape[0]
    #生成全為0的n行num_classes列的值全為0的矩陣
    categorical = np.zeros((n, num_classes), dtype=dtype)
    #np.arange(n)得到每個行的位置值,y裡邊則是每個列的位置值
    categorical[np.arange(n), y] = 1
    #進行reshape矯正
    output_shape = input_shape + (num_classes,)
    categorical = np.reshape(categorical, output_shape)
    return categorical

看過原始碼之後,確實覺得自己的程式碼還需要完善。框架裡的一些api,我們可以先自己想著來寫,然後和原始碼進行對比學習,這是一個很好的學習方法。