diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ef5b7a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +imagenet-vgg-verydeep-19.mat diff --git a/Evaluator.py b/Evaluator.py new file mode 100644 index 0000000..14bef14 --- /dev/null +++ b/Evaluator.py @@ -0,0 +1,31 @@ +import numpy as np +import scipy.optimize as sio + + +class Evaluator: + + def __init__(self, lg_evaluator): + + self._gradient = None + self._lg_eval = lg_evaluator + + # inputs = [input_img] + def optimize(self, input_img, img_rows, img_cols): + + def loss(inputs): + + inputs = np.reshape(inputs, newshape=(1, img_rows, img_cols, 3)) + l, g = self._lg_eval([inputs]) + + self._gradient = g.astype(np.float64) + return l.astype(np.float64) + + def gradient(inputs): + return self._gradient.flatten() + + op = sio.fmin_l_bfgs_b(func=loss, fprime=gradient, x0=input_img, maxiter=500, iprint=10) + print(op) + + op_x = np.reshape(op[0], (1, img_rows, img_cols, 3)) + + return op_x[0] diff --git a/jobscript b/jobscript new file mode 100644 index 0000000..de8b786 --- /dev/null +++ b/jobscript @@ -0,0 +1,9 @@ +#!/bin/bash +#PBS -l nodes=n21:ppn=2 +#PBS -N Unet +#PBS -m e +#PBS -l walltime=48:00:00 +cd $PBS_O_WORKDIR +cd ~/CompVision/project_5_neural_style_transfer/ +module load python cuda +python3 neural_style_transfer.py > output.txt diff --git a/libs/GPUtil/.gitignore b/libs/GPUtil/.gitignore new file mode 100644 index 0000000..72364f9 --- /dev/null +++ b/libs/GPUtil/.gitignore @@ -0,0 +1,89 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject diff --git a/libs/GPUtil/GPUtil/GPUtil.py b/libs/GPUtil/GPUtil/GPUtil.py new file mode 100644 index 0000000..c90e673 --- /dev/null +++ b/libs/GPUtil/GPUtil/GPUtil.py @@ -0,0 +1,311 @@ +# GPUtil - GPU utilization +# +# A Python module for programmically getting the GPU utilization from NVIDA GPUs using nvidia-smi +# +# Author: Anders Krogh Mortensen (anderskm) +# Date: 16 January 2017 +# Web: https://github.com/anderskm/gputil +# +# LICENSE +# +# MIT License +# +# Copyright (c) 2017 anderskm +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from subprocess import Popen, PIPE +from distutils import spawn +import os +import math +import random +import time +import sys +import platform + + +__version__ = '1.4.0' + +class GPU: + def __init__(self, ID, uuid, load, memoryTotal, memoryUsed, memoryFree, driver, gpu_name, serial, display_mode, display_active, temp_gpu): + self.id = ID + self.uuid = uuid + self.load = load + self.memoryUtil = float(memoryUsed)/float(memoryTotal) + self.memoryTotal = memoryTotal + self.memoryUsed = memoryUsed + self.memoryFree = memoryFree + self.driver = driver + self.name = gpu_name + self.serial = serial + self.display_mode = display_mode + self.display_active = display_active + self.temperature = temp_gpu + +def safeFloatCast(strNumber): + try: + number = float(strNumber) + except ValueError: + number = float('nan') + return number + +def getGPUs(): + if platform.system() == "Windows": + # If the platform is Windows and nvidia-smi + # could not be found from the environment path, + # try to find it from system drive with default installation path + nvidia_smi = spawn.find_executable('nvidia-smi') + if nvidia_smi is None: + nvidia_smi = "%s\\Program Files\\NVIDIA Corporation\\NVSMI\\nvidia-smi.exe" % os.environ['systemdrive'] + else: + nvidia_smi = "nvidia-smi" + + # Get ID, processing and memory utilization for all GPUs + try: + p = Popen([nvidia_smi,"--query-gpu=index,uuid,utilization.gpu,memory.total,memory.used,memory.free,driver_version,name,gpu_serial,display_active,display_mode,temperature.gpu", "--format=csv,noheader,nounits"], stdout=PIPE) + stdout, stderror = p.communicate() + except: + return [] + output = stdout.decode('UTF-8') + # output = output[2:-1] # Remove b' and ' from string added by python + #print(output) + ## Parse output + # Split on line break + lines = output.split(os.linesep) + #print(lines) + numDevices = len(lines)-1 + GPUs = [] + for g in range(numDevices): + line = lines[g] + #print(line) + vals = line.split(', ') + #print(vals) + for i in range(12): + # print(vals[i]) + if (i == 0): + deviceIds = int(vals[i]) + elif (i == 1): + uuid = vals[i] + elif (i == 2): + gpuUtil = safeFloatCast(vals[i])/100 + elif (i == 3): + memTotal = safeFloatCast(vals[i]) + elif (i == 4): + memUsed = safeFloatCast(vals[i]) + elif (i == 5): + memFree = safeFloatCast(vals[i]) + elif (i == 6): + driver = vals[i] + elif (i == 7): + gpu_name = vals[i] + elif (i == 8): + serial = vals[i] + elif (i == 9): + display_active = vals[i] + elif (i == 10): + display_mode = vals[i] + elif (i == 11): + temp_gpu = safeFloatCast(vals[i]); + GPUs.append(GPU(deviceIds, uuid, gpuUtil, memTotal, memUsed, memFree, driver, gpu_name, serial, display_mode, display_active, temp_gpu)) + return GPUs # (deviceIds, gpuUtil, memUtil) + + +def getAvailable(order = 'first', limit=1, maxLoad=0.5, maxMemory=0.5, memoryFree=0, includeNan=False, excludeID=[], excludeUUID=[]): + # order = first | last | random | load | memory + # first --> select the GPU with the lowest ID (DEFAULT) + # last --> select the GPU with the highest ID + # random --> select a random available GPU + # load --> select the GPU with the lowest load + # memory --> select the GPU with the most memory available + # limit = 1 (DEFAULT), 2, ..., Inf + # Limit sets the upper limit for the number of GPUs to return. E.g. if limit = 2, but only one is available, only one is returned. + + # Get device IDs, load and memory usage + GPUs = getGPUs() + + # Determine, which GPUs are available + GPUavailability = getAvailability(GPUs, maxLoad=maxLoad, maxMemory=maxMemory, memoryFree=memoryFree, includeNan=includeNan, excludeID=excludeID, excludeUUID=excludeUUID) + availAbleGPUindex = [idx for idx in range(0,len(GPUavailability)) if (GPUavailability[idx] == 1)] + # Discard unavailable GPUs + GPUs = [GPUs[g] for g in availAbleGPUindex] + + # Sort available GPUs according to the order argument + if (order == 'first'): + GPUs.sort(key=lambda x: float('inf') if math.isnan(x.id) else x.id, reverse=False) + elif (order == 'last'): + GPUs.sort(key=lambda x: float('-inf') if math.isnan(x.id) else x.id, reverse=True) + elif (order == 'random'): + GPUs = [GPUs[g] for g in random.sample(range(0,len(GPUs)),len(GPUs))] + elif (order == 'load'): + GPUs.sort(key=lambda x: float('inf') if math.isnan(x.load) else x.load, reverse=False) + elif (order == 'memory'): + GPUs.sort(key=lambda x: float('inf') if math.isnan(x.memoryUtil) else x.memoryUtil, reverse=False) + + # Extract the number of desired GPUs, but limited to the total number of available GPUs + GPUs = GPUs[0:min(limit, len(GPUs))] + + # Extract the device IDs from the GPUs and return them + deviceIds = [gpu.id for gpu in GPUs] + + return deviceIds + +#def getAvailability(GPUs, maxLoad = 0.5, maxMemory = 0.5, includeNan = False): +# # Determine, which GPUs are available +# GPUavailability = np.zeros(len(GPUs)) +# for i in range(len(GPUs)): +# if (GPUs[i].load < maxLoad or (includeNan and np.isnan(GPUs[i].load))) and (GPUs[i].memoryUtil < maxMemory or (includeNan and np.isnan(GPUs[i].memoryUtil))): +# GPUavailability[i] = 1 + +def getAvailability(GPUs, maxLoad=0.5, maxMemory=0.5, memoryFree=0, includeNan=False, excludeID=[], excludeUUID=[]): + # Determine, which GPUs are available + GPUavailability = [1 if (gpu.memoryFree>=memoryFree) and (gpu.load < maxLoad or (includeNan and math.isnan(gpu.load))) and (gpu.memoryUtil < maxMemory or (includeNan and math.isnan(gpu.memoryUtil))) and ((gpu.id not in excludeID) and (gpu.uuid not in excludeUUID)) else 0 for gpu in GPUs] + return GPUavailability + +def getFirstAvailable(order = 'first', maxLoad=0.5, maxMemory=0.5, attempts=1, interval=900, verbose=False, includeNan=False, excludeID=[], excludeUUID=[]): + #GPUs = getGPUs() + #firstAvailableGPU = np.NaN + #for i in range(len(GPUs)): + # if (GPUs[i].load < maxLoad) & (GPUs[i].memory < maxMemory): + # firstAvailableGPU = GPUs[i].id + # break + #return firstAvailableGPU + for i in range(attempts): + if (verbose): + print('Attempting (' + str(i+1) + '/' + str(attempts) + ') to locate available GPU.') + # Get first available GPU + available = getAvailable(order=order, limit=1, maxLoad=maxLoad, maxMemory=maxMemory, includeNan=includeNan, excludeID=excludeID, excludeUUID=excludeUUID) + # If an available GPU was found, break for loop. + if (available): + if (verbose): + print('GPU ' + str(available) + ' located!') + break + # If this is not the last attempt, sleep for 'interval' seconds + if (i != attempts-1): + time.sleep(interval) + # Check if an GPU was found, or if the attempts simply ran out. Throw error, if no GPU was found + if (not(available)): + raise RuntimeError('Could not find an available GPU after ' + str(attempts) + ' attempts with ' + str(interval) + ' seconds interval.') + + # Return found GPU + return available + + +def showUtilization(all=False, attrList=None, useOldCode=False): + GPUs = getGPUs() + if (all): + if (useOldCode): + print(' ID | Name | Serial | UUID || GPU util. | Memory util. || Memory total | Memory used | Memory free || Display mode | Display active |') + print('------------------------------------------------------------------------------------------------------------------------------') + for gpu in GPUs: + print(' {0:2d} | {1:s} | {2:s} | {3:s} || {4:3.0f}% | {5:3.0f}% || {6:.0f}MB | {7:.0f}MB | {8:.0f}MB || {9:s} | {10:s}'.format(gpu.id,gpu.name,gpu.serial,gpu.uuid,gpu.load*100,gpu.memoryUtil*100,gpu.memoryTotal,gpu.memoryUsed,gpu.memoryFree,gpu.display_mode,gpu.display_active)) + else: + attrList = [[{'attr':'id','name':'ID'}, + {'attr':'name','name':'Name'}, + {'attr':'serial','name':'Serial'}, + {'attr':'uuid','name':'UUID'}], + [{'attr':'temperature','name':'GPU temp.','suffix':'C','transform': lambda x: x,'precision':0}, + {'attr':'load','name':'GPU util.','suffix':'%','transform': lambda x: x*100,'precision':0}, + {'attr':'memoryUtil','name':'Memory util.','suffix':'%','transform': lambda x: x*100,'precision':0}], + [{'attr':'memoryTotal','name':'Memory total','suffix':'MB','precision':0}, + {'attr':'memoryUsed','name':'Memory used','suffix':'MB','precision':0}, + {'attr':'memoryFree','name':'Memory free','suffix':'MB','precision':0}], + [{'attr':'display_mode','name':'Display mode'}, + {'attr':'display_active','name':'Display active'}]] + + else: + if (useOldCode): + print(' ID GPU MEM') + print('--------------') + for gpu in GPUs: + print(' {0:2d} {1:3.0f}% {2:3.0f}%'.format(gpu.id, gpu.load*100, gpu.memoryUtil*100)) + else: + attrList = [[{'attr':'id','name':'ID'}, + {'attr':'load','name':'GPU','suffix':'%','transform': lambda x: x*100,'precision':0}, + {'attr':'memoryUtil','name':'MEM','suffix':'%','transform': lambda x: x*100,'precision':0}], + ] + + if (not useOldCode): + if (attrList is not None): + headerString = '' + GPUstrings = ['']*len(GPUs) + for attrGroup in attrList: + #print(attrGroup) + for attrDict in attrGroup: + headerString = headerString + '| ' + attrDict['name'] + ' ' + headerWidth = len(attrDict['name']) + minWidth = len(attrDict['name']) + + attrPrecision = '.' + str(attrDict['precision']) if ('precision' in attrDict.keys()) else '' + attrSuffix = str(attrDict['suffix']) if ('suffix' in attrDict.keys()) else '' + attrTransform = attrDict['transform'] if ('transform' in attrDict.keys()) else lambda x : x + for gpu in GPUs: + attr = getattr(gpu,attrDict['attr']) + + attr = attrTransform(attr) + + if (isinstance(attr,float)): + attrStr = ('{0:' + attrPrecision + 'f}').format(attr) + elif (isinstance(attr,int)): + attrStr = ('{0:d}').format(attr) + elif (isinstance(attr,str)): + attrStr = attr; + elif (sys.version_info[0] == 2): + if (isinstance(attr,unicode)): + attrStr = attr.encode('ascii','ignore') + else: + raise TypeError('Unhandled object type (' + str(type(attr)) + ') for attribute \'' + attrDict['name'] + '\'') + + attrStr += attrSuffix + + minWidth = max(minWidth,len(attrStr)) + + headerString += ' '*max(0,minWidth-headerWidth) + + minWidthStr = str(minWidth - len(attrSuffix)) + + for gpuIdx,gpu in enumerate(GPUs): + attr = getattr(gpu,attrDict['attr']) + + attr = attrTransform(attr) + + if (isinstance(attr,float)): + attrStr = ('{0:'+ minWidthStr + attrPrecision + 'f}').format(attr) + elif (isinstance(attr,int)): + attrStr = ('{0:' + minWidthStr + 'd}').format(attr) + elif (isinstance(attr,str)): + attrStr = ('{0:' + minWidthStr + 's}').format(attr); + elif (sys.version_info[0] == 2): + if (isinstance(attr,unicode)): + attrStr = ('{0:' + minWidthStr + 's}').format(attr.encode('ascii','ignore')) + else: + raise TypeError('Unhandled object type (' + str(type(attr)) + ') for attribute \'' + attrDict['name'] + '\'') + + attrStr += attrSuffix + + GPUstrings[gpuIdx] += '| ' + attrStr + ' ' + + headerString = headerString + '|' + for gpuIdx,gpu in enumerate(GPUs): + GPUstrings[gpuIdx] += '|' + + headerSpacingString = '-' * len(headerString) + print(headerString) + print(headerSpacingString) + for GPUstring in GPUstrings: + print(GPUstring) diff --git a/libs/GPUtil/GPUtil/__init__.py b/libs/GPUtil/GPUtil/__init__.py new file mode 100644 index 0000000..b306dd5 --- /dev/null +++ b/libs/GPUtil/GPUtil/__init__.py @@ -0,0 +1,33 @@ +# GPUtil - GPU utilization +# +# A Python module for programmically getting the GPU utilization from NVIDA GPUs using nvidia-smi +# +# Author: Anders Krogh Mortensen (anderskm) +# Date: 16 January 2017 +# Web: https://github.com/anderskm/gputil +# +# LICENSE +# +# MIT License +# +# Copyright (c) 2017 anderskm +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from .GPUtil import GPU, getGPUs, getAvailable, getAvailability, getFirstAvailable, showUtilization, __version__ diff --git a/libs/GPUtil/GPUtil/demo_GPUtil.py b/libs/GPUtil/GPUtil/demo_GPUtil.py new file mode 100644 index 0000000..596b95a --- /dev/null +++ b/libs/GPUtil/GPUtil/demo_GPUtil.py @@ -0,0 +1,62 @@ +import GPUtil as GPU +import sys +# Get all device ids and their processing and memory utiliazion +# (deviceIds, gpuUtil, memUtil) = GPU.getGPUs() + +# Print os and python version information +print('OS: ' + sys.platform) +print(sys.version) + +# Print package name and version number +print(GPU.__name__ + ' ' + GPU.__version__) + +# Show the utilization of all GPUs in a nice table +GPU.showUtilization() + +# Show all stats of all GPUs in a nice table +GPU.showUtilization(all=True) + +# Get all available GPU(s), ordered by ID in ascending order +print('All available ordered by id: '), +print(GPU.getAvailable(order='first', limit=999)) + +# Get 1 available GPU, ordered by ID in descending order +print('Last available: '), +print(GPU.getAvailable(order='last', limit=1)) + +# Get 1 random available GPU +print('Random available: '), +print(GPU.getAvailable(order='random')) + +# Get 1 available GPU, ordered by GPU load ascending +print('First available weighted by GPU load ascending: '), +print(GPU.getAvailable(order='load', limit=1)) + +# Get all available GPU with max load of 10%, ordered by memory ascending +print('All available weighted by memory load ascending: '), +print(GPU.getAvailable(order='memory', limit=999, maxLoad=0.1)) + +# Get the first available GPU +firstGPU = GPU.getFirstAvailable() +print('First available GPU id:'), +print(firstGPU) + +# Get the first available GPU, where memory usage is less than 90% and processing is less than 80% +firstGPU = GPU.getFirstAvailable(maxMemory=0.9, maxLoad=0.8) +print('First available GPU id (memory < 90%, load < 80%):'), +print(firstGPU) + +# Get the first available GPU, where processing is less than 1% +firstGPU = GPU.getFirstAvailable(attempts=5, interval=5, maxLoad=0.01, verbose=True) +print('First available GPU id (load < 1%):'), +print(firstGPU) +# NOTE: If all your GPUs currently have a load larger than 1%, this step will +# fail. It's not a bug! It is intended to do so, if it does not find an available GPU. + +# Get the first available GPU, where memory usage is less than 1% +firstGPU = GPU.getFirstAvailable(attempts=5, interval=5, maxMemory=0.01, verbose=True) +print('First available GPU id (memory < 1%):'), +print(firstGPU) +# NOTE: If all your GPUs currently have a memory consumption larger than 1%, +# this step will fail. It's not a bug! It is intended to do so, if it does not +# find an available GPU. diff --git a/libs/GPUtil/LICENSE.txt b/libs/GPUtil/LICENSE.txt new file mode 100644 index 0000000..c099b9b --- /dev/null +++ b/libs/GPUtil/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 anderskm + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/GPUtil/README.md b/libs/GPUtil/README.md new file mode 100644 index 0000000..3db6572 --- /dev/null +++ b/libs/GPUtil/README.md @@ -0,0 +1,385 @@ +# GPUtil +`GPUtil` is a Python module for getting the GPU status from NVIDA GPUs using `nvidia-smi`. +`GPUtil` locates all GPUs on the computer, determines their availablity and returns a ordered list of available GPUs. +Availablity is based upon the current memory consumption and load of each GPU. +The module is written with GPU selection for Deep Learning in mind, but it is not task/library specific and it can be applied to any task, where it may be useful to identify available GPUs. + +**Table of Contents** + +1. [Requirements](#requirements) +1. [Installation](#installation) +1. [Usage](#usage) + 1. [Main functions](#main-functions) + 1. [Helper functions](#helper-functions) +1. [Examples](#examples) + 1. [Select first available GPU in Caffe](#select-first-available-gpu-in-caffe) + 1. [Occupy only 1 GPU in TensorFlow](#occupy-only-1-gpu-in-tensorflow) + 1. [Monitor GPU in a separate thread](#monitor-gpu-in-a-separate-thread) +1. [License](#license) + +## Requirements +NVIDIA GPU with latest NVIDIA driver installed. +GPUtil uses the program `nvidia-smi` to get the GPU status of all available NVIDIA GPUs. `nvidia-smi` should be installed automatically, when you install your NVIDIA driver. + +Supports both Python 2.X and 3.X. + +Python libraries: +* subprocess ([The Python Standard Library](https://docs.python.org/3/library/subprocess.html)) +* distutils ([The Python Standard Library](https://docs.python.org/3/library/distutils.html)) +* math ([The Python Standard Library](https://docs.python.org/3/library/math.html)) +* random ([The Python Standard Library](https://docs.python.org/3/library/random.html)) +* time ([The Python Standard Library](https://docs.python.org/3/library/time.html)) +* os ([The Python Standard Library](https://docs.python.org/3/library/os.html)) +* sys ([The Python Standard Library](https://docs.python.org/3/library/sys.html)) +* platform ([The Python Standard Library](https://docs.python.org/3/library/platform.html)) + +Tested on CUDA driver version 390.77 Python 2.7 and 3.5. + +## Installation + +1. Open a terminal (Ctrl+Shift+T) +2. Type `pip install gputil` +3. Test the installation + 1. Open a terminal in a folder other than the GPUtil folder + 2. Start a python console by typing `python` in the terminal + 3. In the newly opened python console, type: + ```python + import GPUtil + GPUtil.showUtilization() + ``` + 4. Your output should look something like following, depending on your number of GPUs and their current usage: + ``` + ID GPU MEM + -------------- + 0 0% 0% + ``` + +### Old way of installation + +1. Download or clone repository to your computer +2. Add GPUtil folder to ~/.bashrc + 1. Open a new terminal (Press Ctrl+Alt+T) + 2. Open bashrc: + ``` + gedit ~/.bashrc + ``` + 3. Added your GPUtil folder to the environment variable `PYTHONPATH` (replace `` with your folder path): + ``` + export PYTHONPATH="$PYTHONPATH:" + + Example: + export PYTHONPATH="$PYTHONPATH:/home/anderskm/github/gputil" + ``` + 4. Save ~/.bashrc and close gedit + 5. Restart your terminal +1. Test the installation + 1. Open a terminal in a folder other than the GPUtil folder + 2. Start a python console by typing `python` in the terminal + 3. In the newly opened python console, type: + ```python + import GPUtil + GPUtil.showUtilization() + ``` + 4. Your output should look something like following, depending on your number of GPUs and their current usage: + ``` + ID GPU MEM + -------------- + 0 0% 0% + ``` + +## Usage + +To include `GPUtil` in your Python code, all you hve to do is included it at the beginning of your script: + +```python +import GPUtil +``` + +Once included all functions are available. The functions along with a short description of inputs, outputs and their functionality can be found in the following two sections. + +### Main functions + +```python +deviceIDs = GPUtil.getAvailable(order = 'first', limit = 1, maxLoad = 0.5, maxMemory = 0.5, includeNan=False, excludeID=[], excludeUUID=[]) +``` +Returns a list ids of available GPUs. Availablity is determined based on current memory usage and load. The order, maximum number of devices, their maximum load and maximum memory consumption are determined by the input arguments. + +* Inputs + * `order` - Deterimines the order in which the available GPU device ids are returned. `order` should be specified as one of the following strings: + * `'first'` - orders available GPU device ids by ascending id (**defaut**) + * `'last'` - orders available GPU device ids by descending id + * `'random'` - orders the available GPU device ids randomly + * `'load'`- orders the available GPU device ids by ascending load + * `'memory'` - orders the available GPU device ids by ascending memory usage + * `limit` - limits the number of GPU device ids returned to the specified number. Must be positive integer. (**default = 1**) + * `maxLoad` - Maximum current relative load for a GPU to be considered available. GPUs with a load larger than `maxLoad` is not returned. (**default = 0.5**) + * `maxMemory` - Maximum current relative memory usage for a GPU to be considered available. GPUs with a current memory usage larger than `maxMemory` is not returned. (**default = 0.5**) + * `includeNan` - True/false flag indicating whether to include GPUs where either load or memory usage is NaN (indicating usage could not be retrieved). (**default = False**) + * `excludeID` - List of IDs, which should be excluded from the list of available GPUs. See `GPU` class description. (**default = []**) + * `excludeUUID` - Same as `excludeID` except it uses the UUID. (**default = []**) +* Outputs + * deviceIDs - list of all available GPU device ids. A GPU is considered available, if the current load and memory usage is less than `maxLoad` and `maxMemory`, respectively. The list is ordered according to `order`. The maximum number of returned device ids is limited by `limit`. + +```python +deviceID = GPUtil.getFirstAvailable(order = 'first', maxLoad=0.5, maxMemory=0.5, attempts=1, interval=900, verbose=False) +``` +Returns the first avaiable GPU. Availablity is determined based on current memory usage and load, and the ordering is determined by the specified order. +If no available GPU is found, an error is thrown. +When using the default values, it is the same as `getAvailable(order = 'first', limit = 1, maxLoad = 0.5, maxMemory = 0.5)` + +* Inputs + * `order` - See the description for `GPUtil.getAvailable(...)` + * `maxLoad` - Maximum current relative load for a GPU to be considered available. GPUs with a load larger than `maxLoad` is not returned. (**default = 0.5**) + * `maxMemory` - Maximum current relative memory usage for a GPU to be considered available. GPUs with a current memory usage larger than `maxMemory` is not returned. (**default = 0.5**) + * `attempts` - Number of attempts the function should make before giving up finding an available GPU. (**default = 1**) + * `interval` - Interval in seconds between each attempt to find an available GPU. (**default = 900** --> 15 mins) + * `verbose` - If `True`, prints the attempt number before each attempt and the GPU id if an available is found. + * `includeNan` - See the description for `GPUtil.getAvailable(...)`. (**default = False**) + * `excludeID` - See the description for `GPUtil.getAvailable(...)`. (**default = []**) + * `excludeUUID` - See the description for `GPUtil.getAvailable(...)`. (**default = []**) +* Outputs + * deviceID - list with 1 element containing the first available GPU device ids. A GPU is considered available, if the current load and memory usage is less than `maxLoad` and `maxMemory`, respectively. The order and limit are fixed to `'first'` and `1`, respectively. + + +```python +GPUtil.showUtilization(all=False, attrList=None, useOldCode=False) +``` +Prints the current status (id, memory usage, uuid load) of all GPUs +* Inputs + * `all` - True/false flag indicating if all info on the GPUs should be shown. Overwrites `attrList`. + * `attrList` - List of lists of `GPU` attributes to display. See code for more information/example. + * `useOldCode` - True/false flag indicating if the old code to display GPU utilization should be used. +* Outputs + * _None_ + +### Helper functions +```python + class GPU +``` +Helper class handle the attributes of each GPU. Quoted descriptions are copied from corresponding descriptions by `nvidia-smi`. +* Attributes for each `GPU` + * `id` - "Zero based index of the GPU. Can change at each boot." + * `uuid` - "This value is the globally unique immutable alphanumeric identifier of the GPU. It does not correspond to any physical label on the board. Does not change across reboots." + * `load` - Relative GPU load. 0 to 1 (100%, full load). "Percent of time over the past sample period during which one or more kernels was executing on the GPU. The sample period may be between 1 second and 1/6 second depending on the product." + * `memoryUtil` - Relative memory usage from 0 to 1 (100%, full usage). "Percent of time over the past sample period during which global (device) memory was being read or written. The sample period may be between 1 second and 1/6 second depending on the product." + * `memoryTotal` - "Total installed GPU memory." + * `memoryUsed` - "Total GPU memory allocated by active contexts." + * `memoryFree` - "Total free GPU memory." + * `driver` - "The version of the installed NVIDIA display driver." + * `name` - "The official product name of the GPU." + * `serial` - This number matches the serial number physically printed on each board. It is a globally unique immutable alphanumeric value. + * `display_mode` - "A flag that indicates whether a physical display (e.g. monitor) is currently connected to any of the GPU's connectors. "Enabled" indicates an attached display. "Disabled" indicates otherwise." + * `display_active` - "A flag that indicates whether a display is initialized on the GPU's (e.g. memory is allocated on the device for display). Display can be active even when no monitor is physically attached. "Enabled" indicates an active display. "Disabled" indicates otherwise." + +```python +GPUs = GPUtil.getGPUs() +``` +* Inputs + * _None_ +* Outputs + * `GPUs` - list of all GPUs. Each `GPU` corresponds to one GPU in the computer and contains a device id, relative load and relative memory usage. + +```python +GPUavailability = GPUtil.getAvailability(GPUs, maxLoad = 0.5, maxMemory = 0.5, includeNan=False, excludeID=[], excludeUUID=[]) +``` +Given a list of `GPUs` (see `GPUtil.getGPUs()`), return a equally sized list of ones and zeroes indicating which corresponding GPUs are available. + +* Inputs + * `GPUs` - List of `GPUs`. See `GPUtil.getGPUs()` + * `maxLoad` - Maximum current relative load for a GPU to be considered available. GPUs with a load larger than `maxLoad` is not returned. (**default = 0.5**) + * `maxMemory` - Maximum current relative memory usage for a GPU to be considered available. GPUs with a current memory usage larger than `maxMemory` is not returned. (**default = 0.5**) + * `includeNan` - See the description for `GPUtil.getAvailable(...)`. (**default = False**) + * `excludeID` - See the description for `GPUtil.getAvailable(...)`. (**default = []**) + * `excludeUUID` - See the description for `GPUtil.getAvailable(...)`. (**default = []**) +* Outputs + * GPUavailability - binary list indicating if `GPUs` are available or not. A GPU is considered available, if the current load and memory usage is less than `maxLoad` and `maxMemory`, respectively. + + +See [demo_GPUtil.py](https://github.com/anderskm/gputil/blob/master/demo_GPUtil.py) for examples and more details. + +## Examples + + +### Select first available GPU in Caffe +In the Deep Learning library [Caffe](http://caffe.berkeleyvision.org/), the user can switch between using the CPU or GPU through their Python interface. +This is done by calling the methods `caffe.set_mode_cpu()` and `caffe.set_mode_gpu()`, respectively. +Below is a minimum working example for selecting the first available GPU with GPUtil to run a Caffe network. + +```python +# Import caffe and GPUtil +import caffe +import GPUtil + +# Set CUDA_DEVICE_ORDER so the IDs assigned by CUDA match those from nvidia-smi +os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" + +# Get the first available GPU +DEVICE_ID_LIST = GPUtil.getFirstAvailable() +DEVICE_ID = DEVICE_ID_LIST[0] # grab first element from list + +# Select GPU mode +caffe.set_mode_gpu() +# Select GPU id +caffe.set_device(DEVICE_ID) + +# Initialize your network here + +``` + +**Note:** At the time of writing this example, the Caffe Python wrapper only supports 1 GPU, although the underlying code supports multiple GPUs. +Calling directly Caffe from the terminal allows for using multiple GPUs. + +### Occupy only 1 GPU in TensorFlow +By default, [TensorFlow](https://www.tensorflow.org/) will occupy all available GPUs when using a gpu as a device (e.g. `tf.device('\gpu:0')`). +By setting the environment variable `CUDA_VISIBLE_DEVICES`, the user can mask which GPUs should be visible to TensorFlow via CUDA (See [CUDA_VISIBLE_DEVICES - Masking GPUs](http://acceleware.com/blog/cudavisibledevices-masking-gpus)). Using GPUtil.py, the CUDA_VISIBLE_DEVICES can be set programmatically based on the available GPUs. +Below is a minimum working example of how to occupy only 1 GPU in TensorFlow using GPUtil. +To run the code, copy it into a new python file (e.g. `demo_tensorflow_gputil.py`) and run it (e.g. enter `python demo_tensorflow_gputil.py` in a terminal). + +**Note:** Even if you set the device you run your code on to a CPU, TensorFlow will occupy all available GPUs. To avoid this, all GPUs can be hidden from TensorFlow with `os.environ["CUDA_VISIBLE_DEVICES"] = ''`. + +```python +# Import os to set the environment variable CUDA_VISIBLE_DEVICES +import os +import tensorflow as tf +import GPUtil + +# Set CUDA_DEVICE_ORDER so the IDs assigned by CUDA match those from nvidia-smi +os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" + +# Get the first available GPU +DEVICE_ID_LIST = GPUtil.getFirstAvailable() +DEVICE_ID = DEVICE_ID_LIST[0] # grab first element from list + +# Set CUDA_VISIBLE_DEVICES to mask out all other GPUs than the first available device id +os.environ["CUDA_VISIBLE_DEVICES"] = str(DEVICE_ID) + +# Since all other GPUs are masked out, the first available GPU will now be identified as GPU:0 +device = '/gpu:0' +print('Device ID (unmasked): ' + str(DEVICE_ID)) +print('Device ID (masked): ' + str(0)) + +# Run a minimum working example on the selected GPU +# Start a session +with tf.Session() as sess: + # Select the device + with tf.device(device): + # Declare two numbers and add them together in TensorFlow + a = tf.constant(12) + b = tf.constant(30) + result = sess.run(a+b) + print('a+b=' + str(result)) + +``` + +Your output should look something like the code block below. Notice how only one of the GPUs are found and created as a tensorflow device. + +``` +I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcublas.so locally +I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcudnn.so locally +I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcufft.so locally +I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcuda.so.1 locally +I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcurand.so locally +Device: /gpu:0 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 0 with properties: +name: TITAN X (Pascal) +major: 6 minor: 1 memoryClockRate (GHz) 1.531 +pciBusID 0000:02:00.0 +Total memory: 11.90GiB +Free memory: 11.76GiB +I tensorflow/core/common_runtime/gpu/gpu_device.cc:906] DMA: 0 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 0: Y +I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: TITAN X (Pascal), pci bus id: 0000:02:00.0) +a+b=42 + +``` +Comment the `os.environ["CUDA_VISIBLE_DEVICES"] = str(DEVICE_ID)` line and compare the two outputs. +Depending on your number of GPUs, your output should look something like code block below. +Notice, how all 4 GPUs are being found and created as a tensorflow device, whereas when `CUDA_VISIBLE_DEVICES` was set, only 1 GPU was found and created. + +``` +I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcublas.so locally +I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcudnn.so locally +I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcufft.so locally +I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcuda.so.1 locally +I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcurand.so locally +Device: /gpu:0 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 0 with properties: +name: TITAN X (Pascal) +major: 6 minor: 1 memoryClockRate (GHz) 1.531 +pciBusID 0000:02:00.0 +Total memory: 11.90GiB +Free memory: 11.76GiB +W tensorflow/stream_executor/cuda/cuda_driver.cc:590] creating context when one is currently active; existing: 0x2c8e400 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 1 with properties: +name: TITAN X (Pascal) +major: 6 minor: 1 memoryClockRate (GHz) 1.531 +pciBusID 0000:03:00.0 +Total memory: 11.90GiB +Free memory: 11.76GiB +W tensorflow/stream_executor/cuda/cuda_driver.cc:590] creating context when one is currently active; existing: 0x2c92040 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 2 with properties: +name: TITAN X (Pascal) +major: 6 minor: 1 memoryClockRate (GHz) 1.531 +pciBusID 0000:83:00.0 +Total memory: 11.90GiB +Free memory: 11.76GiB +W tensorflow/stream_executor/cuda/cuda_driver.cc:590] creating context when one is currently active; existing: 0x2c95d90 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 3 with properties: +name: TITAN X (Pascal) +major: 6 minor: 1 memoryClockRate (GHz) 1.531 +pciBusID 0000:84:00.0 +Total memory: 11.90GiB +Free memory: 11.76GiB +I tensorflow/core/common_runtime/gpu/gpu_device.cc:777] Peer access not supported between device ordinals 0 and 2 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:777] Peer access not supported between device ordinals 0 and 3 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:777] Peer access not supported between device ordinals 1 and 2 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:777] Peer access not supported between device ordinals 1 and 3 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:777] Peer access not supported between device ordinals 2 and 0 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:777] Peer access not supported between device ordinals 2 and 1 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:777] Peer access not supported between device ordinals 3 and 0 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:777] Peer access not supported between device ordinals 3 and 1 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:906] DMA: 0 1 2 3 +I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 0: Y Y N N +I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 1: Y Y N N +I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 2: N N Y Y +I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 3: N N Y Y +I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: TITAN X (Pascal), pci bus id: 0000:02:00.0) +I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:1) -> (device: 1, name: TITAN X (Pascal), pci bus id: 0000:03:00.0) +I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:2) -> (device: 2, name: TITAN X (Pascal), pci bus id: 0000:83:00.0) +I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:3) -> (device: 3, name: TITAN X (Pascal), pci bus id: 0000:84:00.0) +a+b=42 +``` + +### Monitor GPU in a separate thread +If using GPUtil to monitor GPUs during training, it may show 0% utilization. A way around this is to use a separate monitoring thread. +```python +import GPUtil +from threading import Thread +import time + +class Monitor(Thread): + def __init__(self, delay): + super(Monitor, self).__init__() + self.stopped = False + self.delay = delay # Time between calls to GPUtil + self.start() + + def run(self): + while not self.stopped: + GPUtil.showUtilization() + time.sleep(self.delay) + + def stop(self): + self.stopped = True + +# Instantiate monitor with a 10-second delay between updates +monitor = Monitor(10) + +# Train, etc. + +# Close monitor +monitor.stop() +``` + +## License +See [LICENSE](https://github.com/anderskm/gputil/blob/master/LICENSE.txt) diff --git a/libs/GPUtil/setup.cfg b/libs/GPUtil/setup.cfg new file mode 100644 index 0000000..224a779 --- /dev/null +++ b/libs/GPUtil/setup.cfg @@ -0,0 +1,2 @@ +[metadata] +description-file = README.md \ No newline at end of file diff --git a/libs/GPUtil/setup.py b/libs/GPUtil/setup.py new file mode 100644 index 0000000..c560c91 --- /dev/null +++ b/libs/GPUtil/setup.py @@ -0,0 +1,15 @@ +from distutils.core import setup + +setup( + name = 'GPUtil', + packages = ['GPUtil'], + version = '1.4.0', + description = 'GPUtil is a Python module for getting the GPU status from NVIDA GPUs using nvidia-smi.', + author = 'Anders Krogh Mortensen', + author_email = 'anderskroghm@gmail.com', + url = 'https://github.com/anderskm/gputil', + download_url = 'https://github.com/anderskm/gputil/tarball/v1.4.0', + keywords = ['gpu','utilization','load','memory','available','usage','free','select','nvidia'], + classifiers = [], + license = 'MIT', +) diff --git a/libs/gputil-master.zip b/libs/gputil-master.zip new file mode 100755 index 0000000..dc3854e Binary files /dev/null and b/libs/gputil-master.zip differ diff --git a/neural_style_transfer.py b/neural_style_transfer.py new file mode 100644 index 0000000..3e502f8 --- /dev/null +++ b/neural_style_transfer.py @@ -0,0 +1,203 @@ +# Project 5: Neural Style Transfer +# Due May 2nd + +from Evaluator import * +import keras.preprocessing as kp +import matplotlib.pyplot as plt +import numpy as np +import vgg +import keras.backend as K +import keras.layers as kl +import keras.models as km +import os +import sys + + +def content_layer_loss(Fp, Fx): + + _, h, w, d = Fp.get_shape().as_list() + + # Compute sum of residual squares (sse) + sse = K.tf.reduce_sum((Fx - Fp)**2) + + # Note: to access underlying value: w.value + M = w * h + N = d + + # Compute scaling factor + scale = 1.0 / (2 * (M**0.5) * (N**0.5)) + + loss = scale * sse + + return loss + + +def gram_matrix(f): + + # Accepts a (height,width,depth)-sized feature map, + # reshapes to (M,N), then computes the inner product + + _, h, w, d = f.get_shape().as_list() + + M = h * w + N = d + + f = K.tf.reshape(f, shape=(M, N)) + + return K.tf.tensordot(K.tf.transpose(f), f, 1) + + +def style_layer_loss(Fa, Fx): + + _, h, w, d = Fa.get_shape().as_list() + + # Calculate gram matrix of respective feature maps + G_Fa = gram_matrix(Fa) + G_Fx = gram_matrix(Fx) + + # Compute sse between gram matrices + sse = K.tf.reduce_sum((G_Fa - G_Fx)**2) + + # Compute scaling factor + M = w * h + N = d + scale = 1 / (4 * M**2 * N**2) + + loss = scale * sse + + return loss + + +def create_model(input_img, output_layers): + + # Instantiate full VGG model w/ input img + base_model = vgg.VGG19(input_tensor=kl.Input(tensor=K.tf.Variable(input_img))) + return km.Model(inputs=base_model.inputs, outputs=[base_model.get_layer(n).output for n in output_layers]) + + +def pixel_means(img, add=False): + + if add: + + img[:, :, 0] += 103.939 + img[:, :, 1] += 116.779 + img[:, :, 2] += 123.68 + + else: + + img[:, :, 0] -= 103.939 + img[:, :, 1] -= 116.779 + img[:, :, 2] -= 123.68 + + return img + + +on_gpu_server = False +if on_gpu_server is True: + sys.path.append("./libs/GPUtil/GPUtil") + import GPUtil + + os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" + gpus = GPUtil.getAvailable(order="first", limit=1, maxLoad=.2, maxMemory=.2) + if len(gpus) > 0: + os.environ["CUDA_VISIBLE_DEVICES"] = str(gpus[0]) + else: + print("No free GPU") + sys.exit(1) + +# Get image paths +content_path = './main_hall.jpg' +style_path = './starry_night.jpg' + +# Load image to get geometry +temp_img = kp.image.load_img(content_path) +width, height = temp_img.size + +# fix the number of rows, while adapting the aspect ratio +img_rows = 400 +img_cols = int(width * img_rows / height) + +# Load content image +content_img = kp.image.load_img(content_path, target_size=(img_rows, img_cols)) +content_img = kp.image.img_to_array(content_img) + +# Load style image +style_img = kp.image.load_img(style_path, target_size=(img_rows, img_cols)) +style_img = kp.image.img_to_array(style_img) + +# Subtract mean pixel value of +# dataset used to train vgg19 +# from both content and style image +content_img = np.expand_dims(pixel_means(content_img), axis=0) +style_img = np.expand_dims(pixel_means(style_img), axis=0) + +# Define the layer outputs that we are interested in +content_layers = ['block4_conv2'] + +# Create content model +content_model = create_model(content_img, content_layers) + +# Create style model +style_layers = ['block1_relu1', 'block2_relu1', 'block3_relu1', 'block4_relu1', 'block5_relu1'] +style_model = create_model(style_img, style_layers) + +# Instantiate blend model +# Note that the blend model input is same shape/size as content image +blend_base_model = vgg.VGG19(input_tensor=kl.Input(shape=content_img.shape[1:])) + +# blend_outputs = content_outputs + style_outputs +blend_outputs = [blend_base_model.get_layer(n).output for n in content_layers] + [blend_base_model.get_layer(n).output for n in style_layers] + +blend_model = km.Model(inputs=blend_base_model.inputs, outputs=blend_outputs) + +# Separate the model outputs into those intended for comparison with the content layer and the style layer +blend_content_outputs = [blend_model.outputs[0]] +blend_style_outputs = blend_model.outputs[1:] + +content_loss = content_layer_loss(content_model.output, blend_content_outputs[0]) + +content_loss_evaluator = K.function([blend_model.input], [content_loss]) + +# For a correctly implemented gram_matrix, the following code will produce 113934860.0 +fmap = content_model.output + +gram_matrix_evaluator = K.function([content_model.input], [gram_matrix(fmap)]) + +style_loss = 0 +for i in range(5): + style_loss += 0.2 * style_layer_loss(style_model.output[i], blend_style_outputs[i]) + +style_loss_evaluator = K.function([blend_model.input], [style_loss]) + +tv_loss = K.tf.image.total_variation(blend_model.input) + +# Note: these parameters are arbitrarily chosen +alpha = 5.0 +beta = 1e4 +gamma = 1e-3 + +# Calculate total loss as a paramterized lc of content loss, style loss, and total variation loss +total_loss = alpha * content_loss + beta * style_loss + gamma * tv_loss + +# Create total loss evaluator +total_loss_evaluator = K.function([blend_model.input], [total_loss]) + +# Create loss and gradient evaluator. +# Note that tensorflow performs automatic symbolic +# differentiation on the given inputs +grads = K.gradients(total_loss, blend_model.input)[0] +loss_and_grad_evaluator = K.function([blend_model.input], [total_loss, grads]) + +# Generate random data and perform optimization +input_img = np.random.randn(1, img_rows, img_cols, 3) +my_evaluator = Evaluator(loss_and_grad_evaluator) +blend_img = my_evaluator.optimize(input_img, img_rows, img_cols) + +# Once optimization is complete, +# re-add band means we subtracted earlier, +# cast to integer, clip values greater than 255 +blend_img = pixel_means(blend_img).astype(np.int32) + +# Display and save image. +plt.imshow(blend_img) +plt.show()