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,我们可以先自己想着来写,然后和源码进行对比学习,这是一个很好的学习方法。

使用遗传算法优化神经网络模型的超参数(可选超参数包括训练迭代次数,学习率,网络结构等)的代码,原来的神经网络模型如下:import numpy as np import tensorflow as tf from tensorflow.keras.datasets import mnist from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense from tensorflow.keras.utils import to_categorical from tensorflow.keras.optimizers import Adam from sklearn.model_selection import train_test_split # 加载MNIST数据集 (X_train, y_train), (X_test, y_test) = mnist.load_data() # 数据预处理 X_train = X_train.reshape(-1, 28, 28, 1).astype('float32') / 255.0 X_test = X_test.reshape(-1, 28, 28, 1).astype('float32') / 255.0 y_train = to_categorical(y_train) y_test = to_categorical(y_test) # 划分验证集 X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.1, random_state=42) def create_model(): model = Sequential() model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1))) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(64, (3, 3), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(Flatten()) model.add(Dense(64, activation='relu')) model.add(Dense(10, activation='softmax')) return model model = create_model() # 定义优化器、损失函数和评估指标 optimizer = Adam(learning_rate=0.001) loss_fn = tf.keras.losses.CategoricalCrossentropy() metrics = ['accuracy'] # 编译模型 model.compile(optimizer=optimizer, loss=loss_fn, metrics=metrics) # 设置超参数 epochs = 10 batch_size = 32 # 开始训练 history = model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_data=(X_val, y_val)) # 评估模型 test_loss, test_accuracy = model.evaluate(X_test, y_test) print('Test Loss:', test_loss) print('Test Accuracy:', test_accuracy)
06-02
这是一个用于MNIST分类的卷积神经网络模型。为了使用遗传算法优化超参数,你需要先定义一个函数,将神经网络模型和超参数作为参数输入,然后在函数训练模型并返回模型的测试准确率。以下是一个简单的示例代码: ```python import random def evaluate_model(params): # 解析超参数 epochs, batch_size, learning_rate = params # 创建模型 model = create_model() # 定义优化器、损失函数和评估指标 optimizer = Adam(learning_rate=learning_rate) loss_fn = tf.keras.losses.CategoricalCrossentropy() metrics = ['accuracy'] # 编译模型 model.compile(optimizer=optimizer, loss=loss_fn, metrics=metrics) # 训练模型 history = model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_data=(X_val, y_val), verbose=0) # 评估模型 test_loss, test_accuracy = model.evaluate(X_test, y_test, verbose=0) # 返回测试准确率作为适应度 return test_accuracy # 定义遗传算法参数 pop_size = 10 num_generations = 5 mutation_rate = 0.1 elite_size = 2 # 定义超参数搜索空间 param_space = [(5, 32, 0.001), (10, 64, 0.001), (5, 32, 0.01), (10, 64, 0.01)] # 初始化种群 population = [random.choice(param_space) for _ in range(pop_size)] # 开始遗传算法 for i in range(num_generations): # 评估种群每个个体的适应度 fitness_scores = [evaluate_model(params) for params in population] # 选择精英个体 elite_indices = sorted(range(len(fitness_scores)), key=lambda i: fitness_scores[i], reverse=True)[:elite_size] elites = [population[i] for i in elite_indices] # 选择新一代个体 new_population = [] while len(new_population) < pop_size: # 选择父母个体 parent1 = random.choices(population, weights=fitness_scores)[0] parent2 = random.choices(population, weights=fitness_scores)[0] # 交叉产生子代个体 child = [] for j in range(len(parent1)): if random.random() < 0.5: child.append(parent1[j]) else: child.append(parent2[j]) # 变异子代个体 for j in range(len(child)): if random.random() < mutation_rate: child[j] = random.choice(param_space)[j] # 添加子代个体 new_population.append(child) # 添加精英个体 population = elites + new_population # 评估最终种群最优个体的性能 best_params = max(population, key=lambda params: evaluate_model(params)) best_model = create_model() best_model.fit(X_train, y_train, batch_size=best_params[1], epochs=best_params[0], validation_data=(X_val, y_val)) test_loss, test_accuracy = best_model.evaluate(X_test, y_test, verbose=0) print('Best Test Loss:', test_loss) print('Best Test Accuracy:', test_accuracy) ``` 这个代码使用遗传算法搜索超参数空间,每个个体都由三个超参数组成:训练迭代次数、批次大小和学习率。种群大小为10,迭代5代,变异率为0.1,精英个体数量为2。超参数搜索空间包括4个不同的参数组合。每个个体的适应度是其测试准确率,最终选择种群测试准确率最高的个体作为最优超参数,然后使用这些超参数重新训练模型并评估其测试准确率。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值