Skip to content
This repository has been archived by the owner on Jan 2, 2021. It is now read-only.

Residual #129

Open
wants to merge 60 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
fb0db99
Experiments with new convolutional architectures.
alexjc Apr 28, 2016
270524d
Integrated new model, works but doesn't have enough capacity?
alexjc May 2, 2016
a4713ab
Merge commit '23a99313f975a8c0a41e8d05ee448cc4e8c50411' into forward
alexjc May 4, 2016
1bcbf2c
Prototype of feed-forward architecture.
alexjc May 4, 2016
ffb7211
Re-introducing support for multiple phases, multiple iterations.
alexjc May 7, 2016
54070f9
Better default options. 2 phases, 2 iterations.
alexjc May 7, 2016
94004e2
Switching architectures and newly trained network, preparing integrat…
alexjc May 10, 2016
abaab87
Prototype incrementally propagating data down decoder to the output.
alexjc May 10, 2016
bead8a3
Layerwise decoding of the encoded + matched features, work in progress.
alexjc May 11, 2016
d77ed33
New balance parameter replaces both weights. Balance at 0.0 means ful…
alexjc May 11, 2016
7031555
Fix crash when a directory named "content" exists (#88)
longears May 12, 2016
419d752
Cleaning up multi-parameter implementation, supporting patch shapes.
alexjc May 12, 2016
9af43f6
Snap to grid depends on layers. Closes #87.
alexjc May 12, 2016
9c7125a
Reworking arguments to support nargs and lists, adding model configur…
alexjc May 12, 2016
5fbc79f
Support for network that goes all the way up to 6_1.
alexjc May 12, 2016
f3edeab
Layer-wise generation with micro-iterations to match patches.
alexjc May 13, 2016
9a188b8
Fully switching to a layerwise rather than iterative approach, removi…
alexjc May 13, 2016
72361f8
Simplifications to the iterations, better debug logging, reduce load …
alexjc May 13, 2016
9af96f5
Refined the logging, removed unused seeding code.
alexjc May 13, 2016
fbb318f
Major improvements to display, ASCII logo too! All code in forward br…
alexjc May 13, 2016
3354fdb
Merge commit 'b2fac92b27dea18cf1ab8438c981b3537fa9ad06' into forward
alexjc May 13, 2016
7c5374f
Message to download the new model file as uncompressed.
alexjc May 13, 2016
35daa9a
Re-implementing visualization of intermediate frames, 50% slower.
alexjc May 13, 2016
da1c3d6
The blending occurs every frame rather than between phases, fixing th…
alexjc May 14, 2016
fef8036
Tidying up the code, comments, docker build.
alexjc May 14, 2016
57a5e24
Re-ordered code, removed loss calculation, improved logging.
alexjc May 14, 2016
a9377f9
Updating Lasagne to it includes Deconv2D, adding sklearn to requireme…
alexjc May 15, 2016
c0f9c69
Fix for image resize by using PIL fit() rather than thumbnail.
alexjc May 15, 2016
5b7c28f
Updating examples in the README after testing.
alexjc May 16, 2016
e07a699
New photo example.
alexjc May 16, 2016
c784dd9
Replacing the balance parameter with `content-weight` and new paramet…
alexjc May 16, 2016
6358992
Minor tweaks to filenames, code layout, adding prototype content reno…
alexjc May 19, 2016
0d8cf11
Reworking layerwise code to allow for inter-layer iterations.
alexjc May 22, 2016
833889f
Separate processing of layers.
alexjc May 22, 2016
feebb85
Averaging the features from other layers before doing the next iterat…
alexjc May 22, 2016
8eddd55
Re-introducing logging and command-line arguments.
alexjc May 22, 2016
bc10b01
Support for semantic maps again.
alexjc May 22, 2016
c1ddad5
Support for arbitrary layer numbers in feature exchange code.
alexjc May 23, 2016
ac03bad
Re-ordering of the exchange/merge operations.
alexjc May 23, 2016
1f969b7
Switch to new network architecture, simplified layer handling with in…
alexjc May 29, 2016
f81446a
Support for micro-iterations within the macro-passes.
alexjc May 29, 2016
90f7db3
Integrated the feature merging code with the layer evaluation, can us…
alexjc May 29, 2016
288f3ac
Cleaned up default parameters for testing.
alexjc May 31, 2016
ec1d401
First prototype of patch-matching.
alexjc May 31, 2016
1c08f62
Improving patch-matching performance.
alexjc Jun 1, 2016
c4e6ceb
Slow version of 3x3 patch-matching.
alexjc Jun 3, 2016
99ec0a7
Minor performance improvements, major memory improvements. Sub-tensor…
alexjc Jun 3, 2016
f07a188
Increased iteration count for PatchMatch, new network size with poten…
alexjc Jun 9, 2016
3a0418e
Cleaning up patch-matching, stops at 10% improve threshold.
alexjc Jun 9, 2016
21da45f
Working layerwise generation with exchanges between layers as soon as…
alexjc Jun 12, 2016
8ca4787
Switch to JIT-compiled patch-matching.
alexjc Jun 13, 2016
3f81d50
Improved patch-matching using numba and JIT-compiled gu-functions.
alexjc Jun 14, 2016
ebe133e
Using previous layer's matched patches, restored display statistics.
alexjc Jun 14, 2016
4015ade
Normalization of content features and using previous pass for patch m…
alexjc Jun 14, 2016
b413689
Extracted patch score calculation, removed unused code.
alexjc Jun 14, 2016
3eb2fe5
Simplified model code, preparing for custom patch biases.
alexjc Jun 15, 2016
ac57d04
Experimental visualizations of the network.
alexjc Jun 16, 2016
6988155
Patch-variety experimental code using statistics, works in a single p…
alexjc Jun 18, 2016
f08c4d2
Removed content feature normalisation, prototype for matching style g…
alexjc Jun 19, 2016
fae15a7
Experiment with residual network. Features are not as well suited to …
alexjc Jul 3, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 9 additions & 13 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ The algorithm is built for style transfer, but can also generate image analogies

# Synthesize a coastline as if painted by Monet. This uses "*_sem.png" masks for both images.
python3 doodle.py --style samples/Monet.jpg --output samples/Coastline.png \
--device=cpu --iterations=40
--variety 0.0 0.2 --layers 4_1 3_1 --iterations 4 6

# Generate a scene around a lake in the style of a Renoir painting.
python3 doodle.py --style samples/Renoir.jpg --output samples/Landscape.png \
--device=gpu0 --iterations=80
--variety 0.5 --layers 6_1 5_1 4_1 3_1 --iterations 4

Notice the Renoir results look a little better than the Monet. Some rotational variations of the source image could improve the quality of the arch outline in particular.

Expand All @@ -58,12 +58,12 @@ If you want to transfer the style given a source style with annotations, and a t
.. code:: bash

# Synthesize a portrait of Seth Johnson like a Gogh portrait. This uses "*_sem.png" masks for both images.
python3 doodle.py --style samples/Gogh.jpg --content samples/Seth.png \
--output SethAsGogh.png --device=cpu --phases=4 --iterations=40
python3 doodle.py --content samples/Seth.jpg --style samples/Gogh.jpg \
--variety 0.2 0.1 --balance 0.85 1.0 --layers 4_1 3_1 --iterations 6

# Generate what a photo of Vincent van Gogh would look like, using Seth's portrait as reference.
python3 doodle.py --style samples/Seth.jpg --content samples/Gogh.png \
--output GoghAsSeth.png --device=gpu0 --phases=4 --iterations=80
python3 doodle.py --content samples/Gogh.jpg --style samples/Seth.jpg \
--variety 0.0 --balance 0.7 0.8 --layers 4_1 3_1 --iterations 4

To perform regular style transfer without semantic annotations, simply delete or rename the files with the semantic maps. The photo is originally by `Seth Johnson <http://sethjohnson.tumblr.com/post/655063019/this-was-a-project-for-an-art-history-class-turns>`_, and the concept for this style transfer by `Kyle McDonald <https://twitter.com/kcimc>`_.

Expand All @@ -77,13 +77,9 @@ For synthesizing bitmap textures, you only need an input style without anotation

.. code:: bash

# First synthesis uses a darker noise pattern as seed.
python3 doodle.py --style samples/Wall.jpg --output Wall.png\
--seed=noise --seed-range=0:128 --iterations=50 --phases=3

# Second synthesis uses a lighter noise pattern as seed.
python3 doodle.py --style samples/Wall.jpg --output Wall.png\
--seed=noise --seed-range=192:255 --iterations=50 --phases=3
# Generate an image of stones based on the input photograph only.
python3 doodle.py --style samples/Stones.jpg --output Stones.png \
--layers 5_1 4_1 3_1 --iterations 6 4 4 --variety 0.4 0.2 0.1

You can also control the output resolution using ``--output-size=512x512`` parameter—which also depends on the memory you have available. By default the size will be the same as the style image.

Expand Down
4 changes: 2 additions & 2 deletions docker-cpu.df
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ RUN python3 -m pip install -r "requirements.txt"
# Copy only required project files
COPY doodle.py .

# Get a pre-trained neural network (VGG19)
RUN wget -q "https://github.com/alexjc/neural-doodle/releases/download/v0.0/vgg19_conv.pkl.bz2"
# Get a pre-trained neural network, non-commercial & attribution. (GELU2)
RUN wget -q "https://github.com/alexjc/neural-doodle/releases/download/v0.0/gelu2_conv.pkl"

# Set an entrypoint to the main doodle.py script
ENTRYPOINT ["python3", "doodle.py", "--device=cpu"]
4 changes: 2 additions & 2 deletions docker-gpu.df
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ RUN python3 -m pip -q install -r "requirements.txt"
# Copy only required project files
COPY doodle.py .

# Get a pre-trained neural network (VGG19)
RUN wget -q "https://github.com/alexjc/neural-doodle/releases/download/v0.0/vgg19_conv.pkl.bz2"
# Get a pre-trained neural network, non-commercial & attribution. (GELU2)
RUN wget -q "https://github.com/alexjc/neural-doodle/releases/download/v0.0/gelu2_conv.pkl"

# Set an entrypoint to the main doodle.py script
ENTRYPOINT ["python3", "doodle.py", "--device=gpu"]
901 changes: 439 additions & 462 deletions doodle.py

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
colorama
pillow>=3.2.0
Theano>=0.8.1
git+https://github.com/Lasagne/Lasagne.git@0440814#egg=Lasagne==0.2-dev
git+https://github.com/Lasagne/Lasagne.git@31ac7d2#egg=Lasagne==0.2-dev
sklearn>=0.17.1
Binary file modified samples/Monet_sem.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added samples/Stones.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 77 additions & 0 deletions tools/visualize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import matplotlib.pyplot as plt
import numpy as np

import doodle

generator = doodle.NeuralGenerator()
generator.prepare_network()

def calculate_patch_coordinates(l, j, i):
ys, xs, ye, xe = j, i, j, i
while hasattr(l, 'filter_size'):
after = l.filter_size[0]//2
before = l.filter_size[0] - 1 - after
ys -= before
xs -= before
ye += after
xe += after
ys *= l.stride[0]
xs *= l.stride[0]
ye *= l.stride[0]
xe *= l.stride[0]
l = l.input_layer
return ys, xs, ye, xe

import glob
import collections


candidates = collections.defaultdict(list)
for content in glob.glob(doodle.args.content):
image, mask = generator.load_images('content', content, scale=1.0)

feature = generator.model.prepare_image(image)
for layer, encoder in reversed(list(zip(doodle.args.layers, generator.encoders))):
feature = encoder(feature, mask)

x = feature.reshape(feature.shape[:2]+(-1,))[:,:-3,:]
# x = (x - x.mean(axis=(0,2), keepdims=True)) # / x.std(axis=(0,2), keepdims=True)
covariance = np.tensordot(x, x, axes=([2], [2])).mean(axis=(0,2)) / x.shape[2]
np.fill_diagonal(covariance, 0.0)
# print(covariance.shape, covariance.min(), covariance.max())

# subplot.imshow(covariance, interpolation='nearest')

for i in range(feature.shape[1]):
w = feature[:,i:i+1,:,:]
for idx in np.argsort(w.flatten())[-15:]:
_, _, y, x = np.unravel_index(idx, w.shape)
# print('coords', y, x, 'value', )
a, b, c, d = calculate_patch_coordinates(generator.model.network['enc%i_1'%layer], y, x)
img = np.copy(image[max(0,a):min(image.shape[0],c), max(0, b):min(image.shape[1],d)])
candidates[i].append((img, w.flatten()[idx]))

# _, _, y, x = np.unravel_index(feature[0,0,:,:].argmax(), feature.shape)
# print(y, x, calculate_patch_coordinates('enc%i_1'%layer, y, x))

# subplot.set_title('Layer {}'.format(layer))

# subplot.violinplot([feature[:,i,:,:].flatten() for i in range(feature.shape[1])], showmeans=False, showmedians=True)

# x = np.arange(0, feature.shape[1], 1)
# y = [feature.min(axis=(0,2,3)), feature.mean(axis=(0,2,3)), feature.max(axis=(0,2,3))]
# for j in y:
# plt.errorbar(x, j)

fig, axes = plt.subplots(3, 5, figsize=(10, 6), subplot_kw={'xticks': [], 'yticks': []})
fig.subplots_adjust(hspace=0.3, wspace=0.05)
# if not hasattr(axes, 'flat'): axes.flat = [plt]

for i, c in candidates.items():
c.sort(key=lambda x: x[1])
for (img, _), subplot in zip(c[-15:], axes.flat):
subplot.imshow(img, interpolation='nearest')
plt.savefig('channel_{}.png'.format(i))

# plt.show()
# print(i, c[0][1], c[-1][1])