External Memory

プログラミング周辺知識の備忘録メイン

CIFAR-10データのニューラルネットワーク学習

MNISTに続いてCIFAR-10についても機械学習を行うプログラムを作成した。
CIFAR-10は自動車や飛行機、カエルなど10種類の
各6000*10個の32*32pixel RGBカラー画像データです。

画像データは種類に対してほぼランダムのようですが、
一部ある種類の画像が偏っている場合があるようです。
データは以下からダウンロード。
CIFAR-10 and CIFAR-100 datasets

前回と同じく、モデルは
入力と出力のみの2層、及びhidden layerを1層挿入した3層ネットワークです。

import tensorflow as tf
import numpy as np
import math
import time
import os
import pickle


def unpickle(file):
    with open(file, 'rb') as fo:
        dict = pickle.load(fo, encoding='bytes')
    return dict

def cifar10_data(folder):
    train_data = np.zeros((0,3072))
    train_labels = np.zeros((1))
    
    for i in range(1,6):
        fname = os.path.join(folder,"data_batch_{}".format(i))
        data_d = unpickle(fname)
        if i == 1:
            train_data = data_d[b'data']/255
            train_labels = data_d[b'labels']
        else:
            train_data = np.vstack((train_data, data_d[b'data']/255))
            train_labels = np.hstack((train_labels, data_d[b'labels']))
            
    d_dict = unpickle(os.path.join(folder, 'test_batch'))
    test_data = d_dict[b'data']/255
    test_labels = np.array(d_dict[b'labels'])
    
    return train_data,np.eye(10)[train_labels],\
           test_data,np.eye(10)[test_labels]
        
def n_net2(units,l_rate):
    
    T = time.time()
    x = tf.placeholder(tf.float32, [None, units[0]])
    
    W_1 = tf.Variable(
        tf.truncated_normal([units[0], units[1]],
                            stddev=1.0 / math.sqrt(float(units[0]))))
    
    b_1 = tf.Variable(tf.zeros([units[1]]))
    y = tf.matmul(x, W_1) + b_1
    
    y_ = tf.placeholder(tf.float32, [None, units[-1]])

    cross_entropy = tf.reduce_mean(
        tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))

    train_step = tf.train.AdamOptimizer(l_rate).minimize(cross_entropy)

    sess = tf.InteractiveSession()
    tf.global_variables_initializer().run()
    
    train_data,train_labels,test_data,test_labels = cifar10_data("cifar-10-batches-py")
    
    for step in range(1000):
        i = (step * 100) % 50000
        batch_xs = train_data[i:i+100]
        batch_ys = train_labels[i:i+100]
        sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
        
    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    print(sess.run(accuracy, feed_dict={x: test_data,
                                         y_: test_labels}))  
    print("time: {:.4f} s".format(time.time()-T))

    
def n_net3(units,l_rate,keep_p=1.0,lmd=0.0):
    
    T = time.time()
    x = tf.placeholder(tf.float32, [None, units[0]])
    
    W_1 = tf.Variable(
        tf.truncated_normal([units[0], units[1]],
                            stddev=1.0 / math.sqrt(float(units[0]))))
    b_1 = tf.Variable(tf.zeros([units[1]]))
    
    hidden1 = tf.nn.relu(tf.matmul(x, W_1) + b_1)
    
    
    
    keep_prob = tf.placeholder(tf.float32)
    drop_fc = tf.nn.dropout(hidden1,keep_prob)
    
    
    W_h1 = tf.Variable(
        tf.truncated_normal([units[1], units[-1]],
                            stddev=1.0 / math.sqrt(float(units[1]))))
    b_h1 = tf.Variable(tf.zeros([units[-1]]))
    
    y = tf.matmul(drop_fc, W_h1) + b_h1
    
    y_ = tf.placeholder(tf.float32,[None,units[-1]])

    
    L2_n = tf.constant(0.0, dtype=tf.float32)    
    if lmd > 0.0:
        L2_sqr = tf.nn.l2_loss(W_1) + tf.nn.l2_loss(W_h1)
        L2_n = lmd * L2_sqr
        
    cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y_,logits = y))
    train_step = tf.train.AdamOptimizer(l_rate).minimize(cross_entropy + L2_n)
    
    
    sess = tf.InteractiveSession()
    tf.global_variables_initializer().run()
    
    train_data,train_labels,test_data,test_labels = cifar10_data("cifar-10-batches-py")
    
    for step in range(1000):
        i = (step * 100) % 50000
        batch_xs = train_data[i:i+100]
        batch_ys = train_labels[i:i+100]
        sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys, keep_prob: keep_p})
        
    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    print(sess.run(accuracy, feed_dict={x: test_data,
                                         y_: test_labels, keep_prob: keep_p}))
    print("time: {:.4f} s".format(time.time()-T))
    
if __name__ == '__main__':
    units1 = [3072,10]
    n_net2(units1,0.001)
    
    units2 = [3072,2048,10]
    n_net3(units2,0.001)

unpickle関数とcifar10_data関数でデータを読み込んで、
変数に代入できる形に整えた。

データは1ファイルにつき、
列数3072個(32*32*3)、行数10000個の値0-255の二次元uint8 numpy配列です。
最初の32*32エントリに赤、次いで緑、最後に青のチャネル値がある。
255で除して、正規化した。

labelsデータは0-9の値の一次元配列でそれぞれの値は画像の種類を表す。
これらは離散的なので、onehot表現に変更した。

出力
>python cifar10.py
0.3644
time: 3.9231 s
0.4291
time: 64.1100 s

正答率50%くらいは行くかと思っていたが、それほど甘くはなかった。
とはいえ正答率がすぐに飽和しそうなMNISTに比べると
正答率向上のためにいろいろやりようがありそうで面白そうではある。