1+ #! /usr/bin/python
2+ # -*- coding: utf-8 -*-
3+ """
4+
5+ - 1. This model has 1,068,298 paramters and Dorefa compression strategy(weight:1 bit, active: 1 bit),
6+ after 500 epoches' training with GPU,accurcy of 41.1% was found.
7+
8+ - 2. For simplified CNN layers see "Convolutional layer (Simplified)"
9+ in read the docs website.
10+
11+ - 3. Data augmentation without TFRecord see `tutorial_image_preprocess.py` !!
12+
13+ Links
14+ -------
15+ .. https://www.tensorflow.org/versions/r0.9/tutorials/deep_cnn/index.html
16+ .. https://github.com/tensorflow/tensorflow/tree/r0.9/tensorflow/models/image/cifar10
17+
18+ Note
19+ ------
20+ The optimizers between official code and this code are different.
21+
22+ Description
23+ -----------
24+ The images are processed as follows:
25+ .. They are cropped to 24 x 24 pixels, centrally for evaluation or randomly for training.
26+ .. They are approximately whitened to make the model insensitive to dynamic range.
27+
28+ For training, we additionally apply a series of random distortions to
29+ artificially increase the data set size:
30+ .. Randomly flip the image from left to right.
31+ .. Randomly distort the image brightness.
32+ .. Randomly distort the image contrast.
33+
34+ Speed Up
35+ --------
36+ Reading images from disk and distorting them can use a non-trivial amount
37+ of processing time. To prevent these operations from slowing down training,
38+ we run them inside 16 separate threads which continuously fill a TensorFlow queue.
39+
40+ """
41+
42+ import time
43+ import numpy as np
44+ import multiprocessing
45+ import tensorflow as tf
46+ import tensorlayer as tl
47+ from tensorlayer .models import Model
48+ from tensorlayer .layers import (Input , Conv2d , Sign , MaxPool2d , LocalResponseNorm , BinaryConv2d , BinaryDense , Flatten , Dense )
49+
50+
51+ tl .logging .set_verbosity (tl .logging .DEBUG )
52+
53+ # Download data, and convert to TFRecord format, see ```tutorial_tfrecord.py```
54+ # prepare cifar10 data
55+ X_train , y_train , X_test , y_test = tl .files .load_cifar10_dataset (shape = (- 1 , 32 , 32 , 3 ), plotable = False )
56+
57+
58+ def binary_model (input_shape , n_classes ):
59+ in_net = Input (shape = input_shape , name = 'input' )
60+
61+ net = Conv2d (64 , (5 , 5 ), (1 , 1 ), act = 'relu' , padding = 'SAME' , name = 'conv1' )(in_net )
62+ net = Sign (name = 'sign1' )(net )
63+
64+ net = MaxPool2d ((3 , 3 ), (2 , 2 ), padding = 'SAME' , name = 'pool1' )(net )
65+ net = LocalResponseNorm (4 , 1.0 , 0.001 / 9.0 , 0.75 , name = 'norm1' )(net )
66+ net = BinaryConv2d (64 , (5 , 5 ), (1 , 1 ), act = 'relu' , padding = 'SAME' , name = 'bconv1' )(net )
67+
68+ net = LocalResponseNorm (4 , 1.0 , 0.001 / 9.0 , 0.75 , name = 'norm2' )(net )
69+ net = MaxPool2d ((3 , 3 ), (2 , 2 ), padding = 'SAME' , name = 'pool2' )(net )
70+ net = Flatten (name = 'flatten' )(net )
71+ net = Sign (name = 'sign2' )(net )
72+ net = BinaryDense (384 , act = 'relu' , name = 'd1relu' )(net )
73+ net = Sign (name = 'sign3' )(net )
74+ net = BinaryDense (192 , act = 'relu' , name = 'd2relu' )(net )
75+ net = Dense (n_classes , act = None , name = 'output' )(net )
76+ net = Model (inputs = in_net , outputs = net , name = 'binarynet' )
77+ return net
78+
79+ # training settings
80+ net = binary_model ([None , 24 , 24 , 3 ], n_classes = 10 )
81+ batch_size = 128
82+ n_epoch = 50000
83+ learning_rate = 0.0001
84+ print_freq = 5
85+ n_step_epoch = int (len (y_train ) / batch_size )
86+ n_step = n_epoch * n_step_epoch
87+ shuffle_buffer_size = 128
88+
89+ train_weights = net .trainable_weights
90+ optimizer = tf .optimizers .Adam (learning_rate )
91+ cost = tl .cost .cross_entropy
92+
93+ def generator_train ():
94+ inputs = X_train
95+ targets = y_train
96+ if len (inputs ) != len (targets ):
97+ raise AssertionError ("The length of inputs and targets should be equal" )
98+ for _input , _target in zip (inputs , targets ):
99+ # yield _input.encode('utf-8'), _target.encode('utf-8')
100+ yield _input , _target
101+
102+
103+ def generator_test ():
104+ inputs = X_test
105+ targets = y_test
106+ if len (inputs ) != len (targets ):
107+ raise AssertionError ("The length of inputs and targets should be equal" )
108+ for _input , _target in zip (inputs , targets ):
109+ # yield _input.encode('utf-8'), _target.encode('utf-8')
110+ yield _input , _target
111+
112+
113+ def _map_fn_train (img , target ):
114+ # 1. Randomly crop a [height, width] section of the image.
115+ img = tf .image .random_crop (img , [24 , 24 , 3 ])
116+ # 2. Randomly flip the image horizontally.
117+ img = tf .image .random_flip_left_right (img )
118+ # 3. Randomly change brightness.
119+ img = tf .image .random_brightness (img , max_delta = 63 )
120+ # 4. Randomly change contrast.
121+ img = tf .image .random_contrast (img , lower = 0.2 , upper = 1.8 )
122+ # 5. Subtract off the mean and divide by the variance of the pixels.
123+ img = tf .image .per_image_standardization (img )
124+ target = tf .reshape (target , ())
125+ return img , target
126+
127+
128+ def _map_fn_test (img , target ):
129+ # 1. Crop the central [height, width] of the image.
130+ img = tf .image .resize_with_pad (img , 24 , 24 )
131+ # 2. Subtract off the mean and divide by the variance of the pixels.
132+ img = tf .image .per_image_standardization (img )
133+ img = tf .reshape (img , (24 , 24 , 3 ))
134+ target = tf .reshape (target , ())
135+ return img , target
136+
137+
138+
139+ def _train_step (network , X_batch , y_batch , cost , train_op = tf .optimizers .Adam (learning_rate = 0.0001 ), acc = None ):
140+ with tf .GradientTape () as tape :
141+ y_pred = network (X_batch )
142+ _loss = cost (y_pred , y_batch )
143+ grad = tape .gradient (_loss , network .trainable_weights )
144+ train_op .apply_gradients (zip (grad , network .trainable_weights ))
145+ if acc is not None :
146+ _acc = acc (y_pred , y_batch )
147+ return _loss , _acc
148+ else :
149+ return _loss , None
150+
151+ def accuracy (_logits , y_batch ):
152+ return np .mean (np .equal (np .argmax (_logits , 1 ), y_batch ))
153+
154+ # dataset API and augmentation
155+ train_ds = tf .data .Dataset .from_generator (
156+ generator_train , output_types = (tf .float32 , tf .int32 )
157+ ) # , output_shapes=((24, 24, 3), (1)))
158+ train_ds = train_ds .map (_map_fn_train , num_parallel_calls = multiprocessing .cpu_count ())
159+ # train_ds = train_ds.repeat(n_epoch)
160+ train_ds = train_ds .shuffle (shuffle_buffer_size )
161+ train_ds = train_ds .prefetch (buffer_size = 4096 )
162+ train_ds = train_ds .batch (batch_size )
163+ # value = train_ds.make_one_shot_iterator().get_next()
164+
165+ test_ds = tf .data .Dataset .from_generator (
166+ generator_test , output_types = (tf .float32 , tf .int32 )
167+ ) # , output_shapes=((24, 24, 3), (1)))
168+ # test_ds = test_ds.shuffle(shuffle_buffer_size)
169+ test_ds = test_ds .map (_map_fn_test , num_parallel_calls = multiprocessing .cpu_count ())
170+ # test_ds = test_ds.repeat(n_epoch)
171+ test_ds = test_ds .prefetch (buffer_size = 4096 )
172+ test_ds = test_ds .batch (batch_size )
173+ # value_test = test_ds.make_one_shot_iterator().get_next()
174+
175+ for epoch in range (n_epoch ):
176+ start_time = time .time ()
177+
178+ train_loss , train_acc , n_iter = 0 , 0 , 0
179+ for X_batch , y_batch in train_ds :
180+ net .train ()
181+ _loss , acc = _train_step (net , X_batch , y_batch , cost = cost , train_op = optimizer , acc = accuracy )
182+
183+ train_loss += _loss
184+ train_acc += acc
185+ n_iter += 1
186+
187+ print ("Epoch {} of {} took {}" .format (epoch + 1 , n_epoch , time .time () - start_time ))
188+ print (" train loss: {}" .format (train_loss / n_iter ))
189+ print (" train acc: {}" .format (train_acc / n_iter ))
190+
191+ # use training and evaluation sets to evaluate the model every print_freq epoch
192+ if epoch + 1 == 1 or (epoch + 1 ) % print_freq == 0 :
193+ net .eval ()
194+ val_loss , val_acc , n_val_iter = 0 , 0 , 0
195+ for X_batch , y_batch in test_ds :
196+ _logits = net (X_batch ) # is_train=False, disable dropout
197+ val_loss += tl .cost .cross_entropy (_logits , y_batch , name = 'eval_loss' )
198+ val_acc += np .mean (np .equal (np .argmax (_logits , 1 ), y_batch ))
199+ n_val_iter += 1
200+ print (" val loss: {}" .format (val_loss / n_val_iter ))
201+ print (" val acc: {}" .format (val_acc / n_val_iter ))
202+
203+ # use testing data to evaluate the model
204+ net .eval ()
205+ test_loss , test_acc , n_iter = 0 , 0 , 0
206+ for X_batch , y_batch in test_ds :
207+ _logits = net (X_batch )
208+ test_loss += tl .cost .cross_entropy (_logits , y_batch , name = 'test_loss' )
209+ test_acc += np .mean (np .equal (np .argmax (_logits , 1 ), y_batch ))
210+ n_iter += 1
211+ print (" test loss: {}" .format (test_loss / n_iter ))
212+ print (" test acc: {}" .format (test_acc / n_iter ))
0 commit comments