slim = tf.contrib.slim

Layers

for certain functions, assign default values to certain parameters

with slim.arg_scope([func1, func2, ....], arg1=val1, arg2=val2, ....)

https://www.tensorflow.org/api_docs/python/tf/contrib/layers

  • slim.conv2d
  • slim.max_pool2d
  • slim.avg_pool2d
  • slim.dropout
  • slim.batch_norm
  • slim.softmax
  • tf.repeat(inputs, repetitions, layer, args, *kwargs)

class Block(collections.namedtuple(‘Block’, [‘scope’, ‘unit_fn’, ‘args’])):
net = slim.utils.collect_named_outputs(outputs_collections, sc.name, net)

Load pretrained model

Note that initialization function must be associated with sess.

1
2
init_fn = slim.assign_from_checkpoint_fn(checkpoint_path, slim.get_variables_to_restore())
init_fn(sess)

Batch normalization

With slim:

1
2
3
4
5
6
7
8
9
batch_norm_params = {
# Decay for the moving averages.
'decay': batch_norm_decay,
# epsilon to prevent 0s in variance.
'epsilon': batch_norm_epsilon,
# collection containing update_ops.
'updates_collections': tf.GraphKeys.UPDATE_OPS,
}
slim.arg_scope([slim.conv2d], normalizer_fn=slim.batch_norm, normalizer_params=normalizer_params)

For tf.contrib.layers or tf.slim, when is_training=True, mean and variance based on each batch are used and moving_mean and moving_variance are updated if applicable. When is_training=False, loaded moving-mean an moving_variance are used.

To launch the update of moving_mean and moving_variance, special attention needs to be paid because this update operation is detached from gradient descent, which can be realized in the following ways.

The first method:

1
2
3
4
5
6
7
8
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
variables_to_train = _get_variables_to_train()
grads_and_vars = optimizer.compute_gradients(total_loss, variables_to_train)
grad_updates = optimizer.apply_gradients(grads_and_vars)
update_ops.append(grad_updates)
update_op = tf.group(*update_ops)
with tf.control_dependencies([update_op]):
train_op = tf.identity(total_loss)

The second method:

1
2
3
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(update_ops):
train_op = optimizer.minimize(loss)

The third method:

1
train_op = slim.learning.create_train_op(total_loss, optimizer)

Otherwise, one can set updates_collections=None in slim.batch_norm to force the updates in place, but that can have a speed penalty, especially in distributed settings.

However, when trained on small-scale datasets, using moving_mean and moving_variance in the test stage often leads to extremely poor performance (close to random guess). This is due to the code start which renders moving_mean/variance unstable. There are two ways to fix the cold-start issue:

  • in the testing stage, also set is_training=True, i.e., use the mean and variance based on each test batch.

  • decrease batch_norm running average decay from default 0.999 to something like 0.99, which can speed up the start-up. When tuning decay, there is a trade-off between warm-up speed and statistical accuracy. For small-scale datasets, warm-up may take exceedingly long time, e.g., 300 epochs.

without slim: tf.nn.batch_normalization, no moving_mean/variance

1
2
3
4
5
6
7
8
9
10
11
def batchnorm(bn_input):
with tf.variable_scope("batchnorm"):
# this block looks like it has 3 inputs on the graph unless we do this
bn_input = tf.identity(bn_input)

channels = bn_input.get_shape()[3]
offset = tf.get_variable("offset", [channels], dtype=tf.float32, initializer=tf.zeros_initializer())
scale = tf.get_variable("scale", [channels], dtype=tf.float32, initializer=tf.random_normal_initializer(1.0, 0.02))
mean, variance = tf.nn.moments(bn_input, axes=[0, 1, 2], keep_dims=False)
normalized = tf.nn.batch_normalization(bn_input, mean, variance, offset, scale, variance_epsilon=1e-5)
return normalized

Utils

print all model variables

1
2
3
4
5
tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES) # all the global variables
slim.get_model_variables() or tf.get_collection(tf.GraphKeys.MODEL_VARIABLES)
#variables defined by slim (tf.contrib.framework.model_variable)
#excluding gradient variables
tf.trainable_variables() #excluding graident variables and batch_norm variables (moving_mean and moving_variance)

print regularization losses(weight decay) and other losses
1
2
3
slim.losses.get_regularization_losses()
slim.losses.get_losses() # losses except weight decay
slim.losses.get_total_loss(add_regularization_losses=False)

Using multiple GPUs

device = torch.device(“cuda:gpu_id1”)

model = nn.DataParallel(model, [gpu_id1, gpu_id2, …])
model.to(device)

input = input.to(device)

Note that gpu_id1 must be the first gpu in the gpu_list in model.DataParallel(arg1, gpu_list)

Framework Code

  1. Simplest App:

    • MyApp(False)means noredirect while MyApp(True, 'output.txt') will redirect the output to the file output.txt.

    • Derivation from wx.App uses def OnInit(self) while others use def __init__(self)

    • Donnot forget return True

  2. Simplest Frame: frame.Show(), frame.Centre()

  3. A frame with menubar, toolbar, and statusbar: UpdateUIEvents are sent periodically by the framework during idle time to allow the application to check if the state of a control needs to be updated.

    • Append a menu_item with icon,

      qmi = wx.MenuItem(fileMenu, APP_EXIT, '&Quit\tCtrl+Q')
         qmi.SetBitmap(wx.Bitmap('exit.png'))
         fileMenu.AppendItem(qmi)
    • Menu check_item

      self.shtl = viewMenu.Append(wx.ID_ANY, 'Show toolbar', 'Show Toolbar', kind=wx.ITEM_CHECK)
         self.Bind(wx.EVT_MENU, self.ToggleStatusBar, self.shst)
         def ToggleStatusBar(self, e):        
             if self.shst.IsChecked():
              self.statusbar.Show()
             else:
                 self.statusbar.Hide()
  4. Pop a Dialogue box with validator: derivation from wx.PyValidator

  5. A login dialogue before main frame: wx.PyValidator

  6. Notebook with multiple pages

  7. Advanced notebook, user can add new pages

  8. Foldable Pannel

  9. Splash Screen: splash before entering main frame wx.SplashScreen

  10. Extendable Pannel

  11. SplitPanel (hide, show): a horizontally or vertically splited panel, loading html file

  12. File Drag Drop

  13. File Hunter

  14. SpreadSheet

  15. Media Player

  16. Web Browser


Component Code

  1. Bitmap: use bitmap to beautify the appearance, or use the bitmap brush (transparent widgets may be a little troublesome here)

    self.Bind(wx.EVT_PAINT, self.OnPaint)
     def OnPaint(self, event):
         dc = wx.PaintDC(self)
         dc.SetBackgroundMode(wx.TRANSPARENT)
         brush1 = wx.BrushFromBitmap(wx.Bitmap('pattern1.jpg'))
         dc.SetBrush(brush1)
         w, h =  self.GetSize()
         dc.DrawRectangle(0, 0, w, h)
  2. Simplest Button: use lib to build advanced buttons

    • Bind function with building blocks
      self.Bind(wx.EVT_BUTTON, self.OnButton, button) 
         def OnButton(self, event):
    • Note GetChildren(), GetParent(), GetId(), FindWindowById(self.btnId)
  3. Advanced button: bitmap button, toggle button, gradient button

  4. Frame Icon: personalize the frame icon

    con = wx.Icon(path, wx.BITMAP_TYPE_PNG)
     self.SetIcon(icon):
  5. Interaction with Clipboard: paste to and copy from system clipboard

  6. Drop Files to Frame: : wx.PyDropTarget

  7. Help in Frame: when initializing Frame

    pre = wx.PreFrame()
     pre.SetExtraStyle(wx.FRAME_EX_CONTEXTHELP)
     pre.Create(parent, *args, **kwargs)
     self.PostCreate(pre)
  8. Checkbox: use more general event detector to simplify code

    `self.Bind(wx.EVT_CHECKBOX, self.OnCheck)`
    

    e_obj = event.GetEventObject()

  9. dropdown menu

  10. MessageBox

    def ShowMessage(self,event):
         wx.MessageBox('Download completed', 'Info', wx.OK | wx.ICON_INFORMATION)
  11. Open file_dialogue

    dlg = wx.FileDialog(self, "Open File", style=wx.FD_OPEN)
     if dlg.ShowModal() == wx.ID_OK:
         fname = dlg.GetPath()
         handle = open(fname, 'r')
         self.txtctrl.SetValue(handle.read())
         handle.close()
  12. popup menu: right click to pop up the menu

  13. static box: a static box containing components

  14. list ctrl: multi-column list

  15. customtree: a tree-structure file browser

  16. virtual list box

  17. Styled Text: i.e., python-style text

  18. Download Progressbar

  19. About info: info including name, version, copyright, and description

  20. Choose Color Dialogue

    colour_data = wx.ColourData()
     colour = self.GetBackgroundColour()
     colour_data.SetColour(colour)
     colour_data.SetChooseFull(True)
    
     dlg = wx.ColourDialog(self, colour_data)
     if dlg.ShowModal() == wx.ID_OK:
         colour = dlg.GetColourData().GetColour()
         self.SetBackgroundColour(colour)
         self.Refresh()
     dlg.Destroy()
  21. Image Browser with simple editing

  22. Image Slide Show

  23. Search Bar

  24. Timer

    self._timer = wx.Timer(self)
     self.Bind(wx.EVT_TIMER, self.OnTimer, self._timer)
     self._timer.Start(100)
     self._timer.Stop()
  25. Execute Command Line

    import outputwin
     self.output = outputwin.OutputWindow(self)
     self.output.StartProcess("ping %s" % url, blocksize=64)
  26. Music Player

  27. Video Player: First, you need to install MplayerCtrl lib. Secondly, place the mplayer folder under the current working directory.


Layout

  1. wx.BoxSizer: proportion is used to control main direction and wx.EXPAND is used to control the other direction. Note in BoxSizer, alignment is only valid in one direction. AddSpacer(50) is equal to Add((50,50)). AddStretchSpacer() is equal to Add((0,0),proportion=1).

    sizer = wx.BoxSizer(wx.HORIZONTAL)
     sizer.AddSpacer(50)
     sizer.Add(sth,proportion=0, flag=wx.ALL, border=5) #use flag to mark which side has border
     sizer.Add((-1,10)) #add a black space, height=10
     # sizer.Add(sth,proportion=0, wx.EXPAND|wx.RIGHT|wx.ALIGN_RIGHT, border=5)
     sizer.AddSpacer((0,0)) #sizer.AddStretchSpacer()
     self.SetSizer(sizer)
     self.SetInitialSize()
  2. wx.GridSizer: proportion is usually set as 0, use Add((20,20), 1, wx.EXPAND) to take up space.

    wx.GridSizer(2, 2, vgap=0, hgap=0)
     msizer.Add(sth, 0, wx.EXPAND)
  3. wx.FlexGridSizer: make some rows and columns growable.

    fgs.AddGrowableRow(2)
     fgs.AddGrowableCol(1)
  4. wx.GridBagSizer: use pos and span to indicate the location and size.

    sizer = wx.GridBagSizer(vgap=8, hgap=8)
     sizer.Add(sth, (1, 2), (1, 15), wx.EXPAND) 

Notes

  1. Event Propagation: When an event can intrigue multiple events, use event.skip() to guaranttee the occurrence of following events. Take keyevents.py for an example.

  2. Virtual Ride: wx.PyPannel

  3. Bind function which will be checked in the idle time
    self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateEditMenu)

  1. check type

    1
    isinstance(n,int)
  2. list

    1
    2
    3
    4
    5
    6
    7
    8
    t1 = ['a', 'b', 'c'];
    t2 = ['d', 'e', 'f'];
    t1.extend(t2);
    t1.append('g');
    t1 = t1+['g']
    t1.sort();
    del t1[1:3];
    t1.remove('b');
  3. dictionary

    1
    2
    3
    4
    5
    6
    7
    eng2sp = {'one': 'uno', 'two': 'dos', 'three': 'tres'}
    eng2sp.values() #'uno','dos','tres'
    eng2sp.items()
    'one' in eng2sp #true
    inverse = invert_dict(eng2sp)
    d = dict(zip('abc',range(3)))
    d.get(word,0) #d[word] if word in d, 0 otherwise
  4. tupe: similar with list but immutable

  5. file operation

    1
    2
    3
    4
    5
    6
    7
    8
    fout = os.getcwd()
    os.path.abspath('tmp.txt')
    os.path.exists('tmp.txt')
    os.path.isfile/isdir
    os.listdir(cwd)
    fout = open('output.txt','w')
    fout.write('hehe')
    fout.close()

  1. Open SMTP service for your email and obtain the SMTP password.

  2. Create a Python script

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    import win32serviceutil
    import win32service
    import win32event
    import servicemanager
    import smtplib
    import time
    import re
    import sys
    import urllib2

    class Getmyip:
    def visit(self,url):
    opener = urllib2.urlopen(url)
    if url == opener.geturl():
    IPstr = opener.read()
    return re.search('\d+\.\d+\.\d+\.\d+',IPstr).group(0)

    def getip(self):
    myip = self.visit("http://www.net.cn/static/customercare/yourip.asp")
    return myip

    class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "TestService"
    _svc_display_name_ = "Test Service"

    def __init__(self,args):
    win32serviceutil.ServiceFramework.__init__(self,args)
    self.hWaitStop = win32event.CreateEvent(None,0,0,None)
    self.run = True

    def SvcStop(self):
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
    win32event.SetEvent(self.hWaitStop)
    self.run = False

    def SvcDoRun(self):
    while(self.run==True):
    self.main()

    def main(self):
    fromaddr = 'XXX@qq.com'
    toaddrs = 'XXX@qq.com'

    server = smtplib.SMTP_SSL('smtp.qq.com')
    server.set_debuglevel(1)
    print("--- Need Authentication ---")
    username = 'XXX'
    password = 'XXX'
    server.login(username, password)

    prev_msg = ''

    while(True):
    getmyip=Getmyip()
    msg = getmyip.getip()
    if not msg==prev_msg:
    server.sendmail(fromaddr, toaddrs, msg)
    prev_msg = msg
    time.sleep(10)

    server.quit()

    if __name__ == '__main__':
    if len(sys.argv) == 1:
    servicemanager.Initialize()
    servicemanager.PrepareToHostSingle(AppServerSvc)
    servicemanager.StartServiceCtrlDispatcher()
    else:
    win32serviceutil.HandleCommandLine(AppServerSvc)

  3. Make python file into an exe

    1
    pyinstaller -F MyService.py
  4. Make exe into a Windows service

    1
    2
    3
    4
    sc create MyServer binPath=$exe_path
    sc start MyServer
    sc stop MyServer
    sc delete MyServer

Use PIL

1
2
3
4
5
6
7
8
import PIL.ImageDraw
import PIL.Image
import PIL.ImageFont

pil_img = PIL.Image.fromarray(bb_img)
draw = PIL.ImageDraw.Draw(pil_img)
font = PIL.ImageFont.truetype("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf",20)
draw.text((10, 10),"Frame: %09d"%(iframe),(255,0,0),font=font)

Use OpenCV

1
2
import cv2
cv2.putText(cv_img, 'Frame: %d'%(iframe), (10,20), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0,0,255), 3)

  1. Use route to indicate path, 80 is the default port for HTTP.

    1
    2
    3
    4
    5
    6
    7
    import bottle

    @bottle.route('/hello')
    def hello():
    return "Hello World!"

    bottle.run(host='localhost', port=80, debug=True)
  2. Dynamic path V.S. static path. We can use filter such as <id:int> to convert input variables to certain type.

    1
    2
    3
    4
    5
    6
    7
    import bottle

    @bottle.route('/hello/&lt;name>/&lt;address>')
    def hello(name,address):
    return "Hello "+name

    bottle.run(host='localhost', port=80, debug=True)
  3. Use local resources. Pay special attention to the path. Local resource names should start with ‘/‘.

    1
    2
    3
    @bottle.route('/<filename:path>')
    def server_static(filename):
    return bottle.static_file(filename, root='./resource/')
  4. The default HTTP request method for route() is get(), we can use other methods post(), put(), delete(), patch(). The POST method is commonly used for HTML form submission. When entering URL address, GET method is used.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    import bottle

    def check_login(username, password):
    if username=='niuli' and password=='niuli':
    return True
    else:
    return False

    @bottle.get('/login') # or @route('/login')
    def login():
    return '''
    &lt;form action="/login" method="post">
    Username: &lt;input name="username" type="text" />
    Password: &lt;input name="password" type="password" />
    &lt;input value="Login" type="submit" />
    &lt;/form>
    '''

    @bottle.post('/login') # or @route('/login', method='POST')
    def do_login():
    username = bottle.request.forms.get('username')
    password = bottle.request.forms.get('password')
    if check_login(username, password):
    return "&lt;p>Your login information was correct.&lt;/p>"
    else:
    return "&lt;p>Login failed.&lt;/p>"

    bottle.run(host='localhost', port=80, debug=True)
  5. Return local files localhost/filename. Note path:path is important, otherwise the filename containing ‘/‘ may not be correctly recognized.

    1
    2
    3
    4
    5
    from bottle import static_file

    @route(’/<filepath:path>’)
    def server_static(filepath):
    return static_file(filepath, root=’./resource’)
  6. Use redirect to jump to another page: bottle.redirect('/login')

  7. Use the HTML template. In the template file, the lines starting with % are python codes and others are HTML codes. We can include other templates in the current template by using % include('header.tpl', title='Page Title'). Cookies, HTTP header, HTML <form> fields and other request data is available through the global request object.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @bottle.route('/<name>')
    @bottle.view('my_template.html')
    def root(name="default"):
    return bottle.template('my_template', name=name)

    @bottle.post('/login') # or @route('/login', method='POST')
    def do_login():
    username = bottle.request.forms.get('username')
    password = bottle.request.forms.get('password')
    bottle.redirect('/'+username)
  8. Some tricks for helping development

    • bottle.debug(True) The default error page shows a traceback. Templates are not cached. Plugins are applied immediately.

    • run(reloader=True) Every time you edit a module file, the reloader restarts the server process and loads the newest version of your code.

When comparing the efficiency of different libraries, there may exist a few orders of magnitude difference. In the implementation in demand of high efficiency, locate the time-consuming function and replace it with the most efficient library function.

  1. Text: Pandas
    Installation: pip install pandas or conda install pandas

    1
    2
    import pandas as pd
    data = pd.read_csv(text_name, sep=',', header=None)
  2. Image: Pillow-SIMD, skimage, OpenCV, imageio

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import cv2
    import skimage
    import imageio
    from PIL import Image

    #read a 1280x720 image
    pil_im = Image.open(image_name) #0.0057s
    pil_im = pil_im.resize((448,448)) #0.025s

    sk_im = skimage.io.imread(image_name) #0.026s
    sk_im = skimage.transform.resize(sk_im, (448, 448)) #0.060S

    cv_im = cv2.imread(image_name) #0.021s
    cv_im = cv2.resize(cv_im, (448, 448)) #0.0016s

    im = imageio.imread(image_name) #0.033s

    Pillow-SIMD is faster than Pillow, which is not reported here. OpenCV is the most efficient one here.

  3. Video: OpenCV, skvideo, imageio

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import cv2
    import imageio
    import skvideo

    #read 30fps video with each frame 1280x720
    cap = cv2.VideoCapture(video_name)
    ret, frame = cap.read() #0.002s

    vid = imageio.get_reader(video_name, 'ffmpeg')
    for image in vid.iter_data(): #0.004s

    skvideo.setFFmpegPath(os.path.dirname(sys.executable))
    videogen = skvideo.io.vreader(video_name)
    for img in videogen: #0.073s

    For OpenCV in Anaconda, it sometimes fails in reading from video but succeeds in reading from camera. In this case, /usr/bin/python is recommended. imageio and OpenCV are comparable here.

python virtual environment: creat an isolated environment for each python version set, similar with pyenv.

Installation:

For Windows:

Anaconda navigator is a visualization tool for setting up environment and installing packages under each environment.

Python IDEs like Jupyter notebook and spyder can all be treated as packages under each environment.

For Linux:

bash Anaconda2-4.3.1-Linux-x86_64.sh

Environment

list: conda info —envs

create: conda create --name $newenv python=2.7 (if copy, use —clone $oldenv)

activate: source activate $newenv

revert: source deactivate

delete: conda remove —name $newenv —all

package

list: conda list

search: conda search pack

install new packages:

  1. conda install pack
  2. conda install pack=1.8.2 # install certain version
  3. conda install —name env pack
  4. search on http://anaconda.org/, no need to register
  5. pip install pack
  6. install from local pack

Tips: check available pythons: conda search —full-name python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
% Set some nice settings.
grid on;
format long;

% Hold the graphics output until we are good to go.
hold all;

% To create some random test data.
x1 = 100 : 100 : 1000;
raw_y1 = [0.76,0.79,0.80,0.80,0.81,0.82,0.82,0.82,0.82,0.81];
raw_y2 = [0.85,0.81,0.83,0.83,0.82,0.79,0.78,0.80,0.82,0.82];
raw_y3 = [0.85,0.84,0.83,0.83,0.83,0.83,0.82,0.82,0.82,0.82];
legendText = cell(0);

plot(x1,y1,'--go','MarkerSize',5, 'MarkerFaceColor','g', 'LineWidth',3);
legendText(end+1) = { 'CUB' };

plot(x1,y2,':bo', 'MarkerSize',5, 'MarkerFaceColor','b', 'LineWidth',3);
legendText(end+1) = { 'SUN' };

plot(x1,y3,'-ro', 'MarkerSize',5, 'MarkerFaceColor','r', 'LineWidth',3);
legendText(end+1) = { 'Dogs' };

xlim([100 1000]);
ylim([0.72 0.90]);

set(gca,'fontsize',15)

% set sticks on x and y axis
get(gca, 'xtick');
set(gca, 'xtick', 100:100:1000);
get(gca, 'ytick');
set(gca, 'ytick', 0.72:0.02:0.90);

xlabel('# web training instances per category');
ylabel('Accuracy');

legend(legendText,'location','southeast');

hold off;
0%