深度学习(二):用CNTK在Python下实现一个简单的FeedForward网络

本次考虑用CNTK实现一个最简单的前馈网络,所使用的数据集为OpenML上一个one_hundred_plants_shape,原数据集为arff格式,本人已转换为csv格式上传到了百度网盘中。数据集为1600*65,前64列为特征值,最后一列为分类号,从1至100,每一类16组数据。cntk版本为beta 5。主要用到的模块为cntk.learner、cntk.trainer、cntk.ops、cntk.utils。learner模块主要包含了一些随机优化算法如sgd()、momentum_sgd()等。trainer模块主要在训练模型时使用,常用的函数为train_minibatch()和test_minibatch()。ops模块中包含了各种运算函数,也有计算模型优度的函数cross_entropy_with_softmax()、classification_error()。

一般而言,训练神经网络需要以下几个步骤:

  1. 读取数据并对数据进行处理;
  2. 建立神经网络模型;
  3. 初始化学习器learner与训练器;
  4. 训练模型;
  5. 对模型进行测试。

读取数据并进行处理

在python中读取数据可以使用numpy的genfromtxt(),用delimiter设置分隔符。此外在CNTK中,目标向量需要转换为张量才能进行处理,因此需要预处理。假设目标的分类向量为[1,2,3],那么在CNTK中就需要转换为[[1,0,0],[0,1,0],[0,0,1]]。而在本数据集中,总共有100种分类,因此需要将每一个分类值转换为一个100维的向量,转换之后的分类张量为1600*100,由toTensor()函数完成。
代码如下:
dataset=np.genfromtxt('one-hundred-plants-shape.csv',skip_header=1,delimiter=',')
features_data=dataset[:,0:63]
targets_data=np.reshape(dataset[:,-1],[1600,1])

def toTensor(li):
    class_ind=[li== i for i in range(int(np.unique(li).shape[0]))]
    li= np.asarray(np.hstack(class_ind), dtype=np.float32)
    return li

targets_data=toTensor(targets_data)

建立神经网络模型

建立神经网络模型所需要用到的主要为Sequential()和Laystack()函数。Sequential()可以将各种神经层叠加在一起,其参数为一个多个神经层组成的向量。在cntk中提供的神经层有10种,对于简单前馈网络 而言,只需要使用其中的Dense()层就可以了。代码中的features和targets类似于一个容器,用于盛放输入和目标数据,,需要使用input_variable()函数,传递的参数为数据的维度。
代码如下:
input_dim=63
output_dim=100
features=input_variable(input_dim,np.float32)
targets=input_variable(output_dim,np.float32)

model=Sequential([
        Dense(200,activation=sigmoid),
        Dense(150,activation=sigmoid),
        Dense(120,activation=relu),
        Dense(output_dim)
    ])(features)
cs=cross_entropy_with_softmax(model,targets)
ce=classification_error(model,targets)
Dense()的参数为输出的维度和激活函数,一般有sigmoid、relu等。在用Sequential()时有两点需要注意的地方,一是最后一层的输出维度必须与分类张量的维度一致,在本例中就为100维。二是在模型之后需要添加用input_variable()创建的输入数据容器,如本例中sequential后跟的features,否则在定义trainer时,会出现未知维度的错误。

初始化学习器learner与训练器trainer

这一步主要用到Trainer()构造器和lenrner模型中的随机优化函数。max_epoch为最大的epoch次数,一个epoch为向网络传递所有的样本数据,50 epoch就会像网络传递50次所有样本的数据。而batch_size为每一个epoch中,每一次向网络传递多少样本。一般使用小的epoch可以提高精度。
向Trainer()传递的参数为模型、loss function、evaluation function以及学习器,loss function为优化的目标函数,学习器就是所使用的优化算法,本例中为cross_entroy_with_softmax()。evaluation function为判断模型拟合优度的函数。学习中主要定义学习率的变化情况,一般在各个模型中是通用的。
代码如下:evaluation function
max_epoch=50
sample_size=1600
batch_size=10

lr_per_sample=[0.001]*10+[0.005]*10+[0.001]
lr_schedule=learning_rate_schedule(lr_per_sample,UnitType.sample,max_epoch)
mm_time_constant=[0]*5+[1024]
mm_schedule=momentum_as_time_constant_schedule(mm_time_constant,max_epoch)

learner=momentum_sgd(model.parameters,lr_schedule,mm_schedule)
trainer=Trainer(model,cs,ce,learner)
progress_printer=ProgressPrinter(tag='Training')
代码中的ProgressPrinter()用于打印每一个epoch的结果。

对模型进行测试主要用到test_minibatch函数,过程与训练模型类似,本次不讨论这个问题。
以上代码的实际运行结果如下:
Finished Epoch [44]: [Training] loss = 4.603901 * 1600, metric = 99.0% * 1600 0.441s (3626.3 samples per second)
Finished Epoch [45]: [Training] loss = 4.603828 * 1600, metric = 99.0% * 1600 0.454s (3526.2 samples per second)
Finished Epoch [46]: [Training] loss = 4.603758 * 1600, metric = 99.0% * 1600 0.473s (3384.3 samples per second)
Finished Epoch [47]: [Training] loss = 4.603689 * 1600, metric = 99.0% * 1600 0.444s (3605.8 samples per second)
Finished Epoch [48]: [Training] loss = 4.603622 * 1600, metric = 99.0% * 1600 0.498s (3210.8 samples per second)
Finished Epoch [49]: [Training] loss = 4.603556 * 1600, metric = 99.0% * 1600 0.450s (3553.7 samples per second)
Finished Epoch [50]: [Training] loss = 4.603492 * 1600, metric = 99.0% * 1600 0.481s (3327.8 samples per second)

其中的metric为模型的错误率,可以看到为99%,非常不理想,不过本次仅作为一个例子,重在实现过程。

你可能感兴趣的:(机器学习)