Optuna LightGBM RuntimeError Directions - lightgbm

I'm attempting to tune the hyperparameters of my lightGBM model but I keep getting the same error:
RuntimeError: A single direction cannot be retrieved from a multi-objective study. Consider using Study.directions to retrieve a list containing all directions.
Which is really confusing because I'm following the advice explained in this answer which means I'm passing a list of directions to the study. Any and all help will be greatly appreciated.
def objective(trial, X, y, group):
param = {
"objective": "binary",
"metric": "auc",
"verbosity": -1,
"boosting_type": "gbdt",
"lambda_l1": trial.suggest_float("lambda_l1", 1e-8, 10.0, log=True),
"lambda_l2": trial.suggest_float("lambda_l2", 1e-8, 10.0, log=True),
"num_leaves": trial.suggest_int("num_leaves", 2, 256),
"feature_fraction": trial.suggest_float("feature_fraction", 0.4, 1.0),
"bagging_fraction": trial.suggest_float("bagging_fraction", 0.4, 1.0),
"bagging_freq": trial.suggest_int("bagging_freq", 1, 7),
"min_child_samples": trial.suggest_int("min_child_samples", 5, 100),
}
cv = StratifiedGroupKFold(n_splits=5, shuffle=True, random_state=RANDOM_STATE)
cv_scores = np.empty(5)
auc_scores = np.empty(5)
for idx, (train_idx, test_idx) in enumerate(cv.split(X, y,groups=group)):
X_train, X_test = X.iloc[train_idx], X.iloc[test_idx]
y_train, y_test = y.iloc[train_idx], y.iloc[test_idx]
pruning_callback = optuna.integration.LightGBMPruningCallback(trial, "auc")
model = lgb.LGBMClassifier(**param)
model.fit(
X_train,
y_train,
eval_set=[(X_test, y_test)],
early_stopping_rounds=100,
callbacks=[pruning_callback])
preds = model.predict_proba(X_test)
cv_scores[idx] = log_loss(y_test, preds)
auc_scores[idx] = roc_auc_score(y_test, preds)
return np.mean(cv_scores), np.mean(auc_scores)
study = optuna.create_study(directions=["minimize", "maximize"], study_name="LGBM Classifier")
func = lambda trial: objective(trial, X, y, group)
study.optimize(func, n_trials=2)

Related

Translate CNN from keras to pytorch

I need some help. I am trying to convert a CNN from keras to pytorch. I am reconstructing an MR image. The input is the image coming from the scanner in the fourier domain and the output is the reconstructed image. The input image has two channels (first channel: real part, second channel: imaginary part). Unfortunately, the results are quite different, so I believe I am doing something wrong. I just cannot find out myself what it is. Here is the keras code:
def AUTOMAP_Basic_Model(param):
fc_1 = keras.Input(shape=(64,64,2), name='input')
fc_2 = layers.Conv2D(64,(64,1),strides=1,padding='same',activation='relu')(fc_1)
fc_4 = layers.Conv2D(64,(1,64),strides=1,padding='same',activation='relu')(fc_2)
fc_4 = layers.Conv2D(64,(64,1),strides=1,padding='same',activation='relu')(fc_4)
fc_5 = layers.Conv2D(64,(1,64),strides=1,padding='same',activation='relu')(fc_4)
c_1 = layers.Conv2D(64,5,strides=1,padding='same',activation='relu')(fc_5)
c_2 = layers.Conv2D(64,5,strides=1,padding='same',activation='relu')(c_1)
c_3 = layers.Conv2DTranspose(1,7,strides=1,activation='sigmoid',padding='same')(c_2)
model = keras.Model(inputs = fc_1,outputs = c_3)
return model
And this is my translation to pytorch:
class AUTOMAP_Basic_Model(nn.Module):
def __init__(self, inputShape, nrFilters):
super(AUTOMAP_Basic_Model, self).__init__()
self.conv1 = nn.Conv2d(2, 64, (64,1), padding='same')
self.relu = nn.ReLU()
self.conv2 = nn.Conv2d(64, 64, (1,64), padding ='same')
self.conv3 = nn.Conv2d(64, 64, (64,1), padding='same')
self.conv4 = nn.Conv2d(64,64,5,padding='same')
self.conv5 = nn.Conv2d(64,64,5,padding='same')
self.convTranspose = nn.ConvTranspose2d(64,1,7,padding=3,output_padding=0)
self.sigmoid = nn.Sigmoid()
self.tan = nn.Tanh()
def forward(self, x):
batch_size = len(x)
out = self.conv1(x)
out = self.relu(out)
out = self.conv2(out)
out = self.relu(out)
out = self.conv3(out)
out = self.relu(out)
out = self.conv2(out)
out = self.relu(out)
out = self.conv4(out)
out = self.relu(out)
out = self.conv5(out)
out = self.relu(out)
out = self.convTranspose(out)
out=self.sigmoid(out)
return out
I am new to pytorch, thats why I do not know what could be wrong. While the keras model is converging to the right image, the pytorch model is giving me a constant value of 0.45 for every pixel in the image.
It seems like you have some strange ordering and naming in both Keras and PyTorch. In the first one fc_3 is missing, which might still be viable but I don't understand why.
In the PyTorch implementation, you need to have 4 conv layer (fc_2, fc_3, fc_4, fc_5), but you only implemented 3 (conv1, conv2, conv3).
I'd rewrite the model with something like:
class AUTOMAP_Basic_Model(nn.Module):
def __init__(self, inputShape, nrFilters):
super(AUTOMAP_Basic_Model, self).__init__()
self.conv1 = nn.Conv2d(2, 64, (64, 1), padding='same')
self.conv2 = nn.Conv2d(64, 64, (1, 64), padding='same')
self.conv3 = nn.Conv2d(64, 64, (64, 1), padding='same')
self.conv4 = nn.Conv2d(64, 64, (1, 64), padding='same')
self.conv5 = nn.Conv2d(64, 64, 5, padding='same')
self.conv6 = nn.Conv2d(64, 64, 5, padding='same')
self.relu = nn.ReLU(inplace=True)
self.convTranspose = nn.ConvTranspose2d(64, 1, 7, padding=3, output_padding=0)
self.sigmoid = nn.Sigmoid()
self.tan = nn.Tanh()
def forward(self, x):
batch_size = len(x)
out = self.relu(self.conv1(x))
out = self.relu(self.conv2(out))
out = self.relu(self.conv3(out))
out = self.relu(self.conv4(out))
out = self.relu(self.conv5(out))
out = self.relu(self.conv6(out))
out = self.convTranspose(out)
out = self.sigmoid(out)
return out
I'd also suggest using Conv+BN+Relu

reverse the color for heatmap colorbar [duplicate]

I would like to know how to simply reverse the color order of a given colormap in order to use it with plot_surface.
The standard colormaps also all have reversed versions. They have the same names with _r tacked on to the end. (Documentation here.)
The solution is pretty straightforward. Suppose you want to use the "autumn" colormap scheme. The standard version:
cmap = matplotlib.cm.autumn
To reverse the colormap color spectrum, use get_cmap() function and append '_r' to the colormap title like this:
cmap_reversed = matplotlib.cm.get_cmap('autumn_r')
In matplotlib a color map isn't a list, but it contains the list of its colors as colormap.colors. And the module matplotlib.colors provides a function ListedColormap() to generate a color map from a list. So you can reverse any color map by doing
colormap_r = ListedColormap(colormap.colors[::-1])
As of Matplotlib 2.0, there is a reversed() method for ListedColormap and LinearSegmentedColorMap objects, so you can just do
cmap_reversed = cmap.reversed()
Here is the documentation.
As a LinearSegmentedColormaps is based on a dictionary of red, green and blue, it's necessary to reverse each item:
import matplotlib.pyplot as plt
import matplotlib as mpl
def reverse_colourmap(cmap, name = 'my_cmap_r'):
"""
In:
cmap, name
Out:
my_cmap_r
Explanation:
t[0] goes from 0 to 1
row i: x y0 y1 -> t[0] t[1] t[2]
/
/
row i+1: x y0 y1 -> t[n] t[1] t[2]
so the inverse should do the same:
row i+1: x y1 y0 -> 1-t[0] t[2] t[1]
/
/
row i: x y1 y0 -> 1-t[n] t[2] t[1]
"""
reverse = []
k = []
for key in cmap._segmentdata:
k.append(key)
channel = cmap._segmentdata[key]
data = []
for t in channel:
data.append((1-t[0],t[2],t[1]))
reverse.append(sorted(data))
LinearL = dict(zip(k,reverse))
my_cmap_r = mpl.colors.LinearSegmentedColormap(name, LinearL)
return my_cmap_r
See that it works:
my_cmap
<matplotlib.colors.LinearSegmentedColormap at 0xd5a0518>
my_cmap_r = reverse_colourmap(my_cmap)
fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = my_cmap, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = my_cmap_r, norm=norm, orientation='horizontal')
EDIT
I don't get the comment of user3445587. It works fine on the rainbow colormap:
cmap = mpl.cm.jet
cmap_r = reverse_colourmap(cmap)
fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = cmap, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = cmap_r, norm=norm, orientation='horizontal')
But it especially works nice for custom declared colormaps, as there is not a default _r for custom declared colormaps. Following example taken from http://matplotlib.org/examples/pylab_examples/custom_cmap.html:
cdict1 = {'red': ((0.0, 0.0, 0.0),
(0.5, 0.0, 0.1),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 1.0),
(0.5, 0.1, 0.0),
(1.0, 0.0, 0.0))
}
blue_red1 = mpl.colors.LinearSegmentedColormap('BlueRed1', cdict1)
blue_red1_r = reverse_colourmap(blue_red1)
fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = blue_red1, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = blue_red1_r, norm=norm, orientation='horizontal')
There is no built-in way (yet) of reversing arbitrary colormaps, but one simple solution is to actually not modify the colorbar but to create an inverting Normalize object:
from matplotlib.colors import Normalize
class InvertedNormalize(Normalize):
def __call__(self, *args, **kwargs):
return 1 - super(InvertedNormalize, self).__call__(*args, **kwargs)
You can then use this with plot_surface and other Matplotlib plotting functions by doing e.g.
inverted_norm = InvertedNormalize(vmin=10, vmax=100)
ax.plot_surface(..., cmap=<your colormap>, norm=inverted_norm)
This will work with any Matplotlib colormap.
There are two types of LinearSegmentedColormaps. In some, the _segmentdata is given explicitly, e.g., for jet:
>>> cm.jet._segmentdata
{'blue': ((0.0, 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65, 0, 0), (1, 0, 0)), 'red': ((0.0, 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89, 1, 1), (1, 0.5, 0.5)), 'green': ((0.0, 0, 0), (0.125, 0, 0), (0.375, 1, 1), (0.64, 1, 1), (0.91, 0, 0), (1, 0, 0))}
For rainbow, _segmentdata is given as follows:
>>> cm.rainbow._segmentdata
{'blue': <function <lambda> at 0x7fac32ac2b70>, 'red': <function <lambda> at 0x7fac32ac7840>, 'green': <function <lambda> at 0x7fac32ac2d08>}
We can find the functions in the source of matplotlib, where they are given as
_rainbow_data = {
'red': gfunc[33], # 33: lambda x: np.abs(2 * x - 0.5),
'green': gfunc[13], # 13: lambda x: np.sin(x * np.pi),
'blue': gfunc[10], # 10: lambda x: np.cos(x * np.pi / 2)
}
Everything you want is already done in matplotlib, just call cm.revcmap, which reverses both types of segmentdata, so
cm.revcmap(cm.rainbow._segmentdata)
should do the job - you can simply create a new LinearSegmentData from that. In revcmap, the reversal of function based SegmentData is done with
def _reverser(f):
def freversed(x):
return f(1 - x)
return freversed
while the other lists are reversed as usual
valnew = [(1.0 - x, y1, y0) for x, y0, y1 in reversed(val)]
So actually the whole thing you want, is
def reverse_colourmap(cmap, name = 'my_cmap_r'):
return mpl.colors.LinearSegmentedColormap(name, cm.revcmap(cmap._segmentdata))

Python spyder + tensorflow cross validation freezes on Windows 10

On Windows 10, I have installed Anaconda and launched Spyder. I have also successfully installed Theano, Tensorflow and Keras, since when I execute
import keras
the console outputs
Using Tensorflow Backend
When I compile and fit the neural network it runs fine. But when I try to run k-fold cross validation, combining the scikit-learn via a keras wrapper and using the parameter n_jobs = -1 (and generally n_jobs with whatever value, thus having multiprocessing), the console just freezes forever until restarting kernel manually or terminating Spyder.
Another problem, when I try to run some parameter tuning using GridSearchCV, for i.e. 100 epochs, it doesn't freeze but it outputs epoch 1/1 instead of 1/100 and generally it gives bad results, not logical (i.e. it runs only for a couple of minutes, while normally it would take hours!).
My code is:
# Part 1 - Data Preprocessing
# Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# Importing the dataset
dataset = pd.read_csv('Churn_Modelling.csv')
X = dataset.iloc[:, 3:13].values
y = dataset.iloc[:, 13].values
# Encoding categorical data
# Encoding the Independent Variable
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
labelencoder_X_1 = LabelEncoder()
X[:, 1] = labelencoder_X_1.fit_transform(X[:, 1])
labelencoder_X_2 = LabelEncoder()
X[:, 2] = labelencoder_X_2.fit_transform(X[:, 2])
onehotencoder = OneHotEncoder(categorical_features = [1])
X = onehotencoder.fit_transform(X).toarray()
# Avoiding the dummy variable trap
X = X[:, 1:]
# Splitting the dataset into the Training set and Test set
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
# Feature Scaling
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
# Part 2 - Now let's make the ANN!
# Importing the Keras libraries and packages
import keras
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
# Initialising the ANN
classifier = Sequential()
# Adding the input layer and the first hidden layer with dropout
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu', input_dim = 11))
classifier.add(Dropout(rate = 0.1)) # p should vary from 0.1 to 0.4, NOT HIGHER, because then we will have under-fitting.
# Adding the second hidden layer with dropout
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu'))
classifier.add(Dropout(rate = 0.1))
# Adding the output layer
classifier.add(Dense(units = 1, kernel_initializer = 'uniform', activation = 'sigmoid'))
# Compiling the ANN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
# Fitting the ANN to the Training set
classifier.fit(X_train, y_train, batch_size = 10, epochs = 100)
# Part 3 - Making predictions and evaluating the model
# Predicting the Test set results
y_pred = classifier.predict(X_test)
y_pred = (y_pred > 0.5)
# Making the Confusion Matrix
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, y_pred)
new_prediction = classifier.predict(sc.transform(np.array([[0, 0, 600, 1, 40, 3, 60000, 2, 1, 1, 50000]])))
new_prediction = (new_prediction > 0.5)
#Part 4 = Evaluating, Improving and Tuning the ANN
# Evaluating the ANN
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import cross_val_score
from keras.models import Sequential
from keras.layers import Dense
def build_classifier():
classifier = Sequential()
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu', input_dim = 11))
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu'))
classifier.add(Dense(units = 1, kernel_initializer = 'uniform', activation = 'sigmoid'))
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
return classifier
classifier = KerasClassifier(build_fn = build_classifier, batch_size = 10, nb_epoch = 100)
accuracies = cross_val_score(estimator = classifier, X = X_train, y = y_train, cv = 10, n_jobs = -1)
mean = accuracies.mean()
variance = accuracies.std()
# Improving the ANN
# Tuning the ANN
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import GridSearchCV
from keras.models import Sequential
from keras.layers import Dense
def build_classifier(optimizer):
classifier = Sequential()
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu', input_dim = 11))
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu'))
classifier.add(Dense(units = 1, kernel_initializer = 'uniform', activation = 'sigmoid'))
classifier.compile(optimizer = optimizer, loss = 'binary_crossentropy', metrics = ['accuracy'])
return classifier
classifier = KerasClassifier(build_fn = build_classifier)
parameters = {"batch_size": [25, 32],
"nb_epoch": [100, 500],
"optimizer": ["adam", "rmsprop"]}
grid_search = GridSearchCV(estimator = classifier,
param_grid = parameters,
scoring = "accuracy",
cv = 10)
grid_search = grid_search.fit(X_train, y_train)
best_parameters = grid_search.best_params_
best_accuracy = grid_search.best_score_
Also, for n_jobs = 1, it runs but says epoch 1/1 and runs 10 times, which is the k-fold value. That means that it recognizes nb_epoch = 1 and not 100 for some reason.
Finally, I tried enclosing the cross_val_score() into a class:
class run():
def __init__(self):
cross_val_score(estimator = classifier, X = X_train, y = y_train, cv = 10, n_jobs = -1)
if __name__ == '__main__':
run()
or have it only with the if condition:
if __name__ == '__main__':
cross_val_score(estimator = classifier, X = X_train, y = y_train, cv = 10, n_jobs = -1)
but it doesn't work either, it freezes again.
Can anyone help me out solving these issues? What is going on, what can I do to solve these so everything runs properly?
Thank you in advance.
it seems Windows has an issue with "n_jobs", remove it in your "accuracies=" code and it will work, downside is it may take a while but at least it will work.

CNN model on image classification is not convergent, which is based on Tensorflow

I try to train a CNN model, 2 classes, which is based on tensorflow to do the image classification.
I have tried much modification about epochs, learning rate, batch size and the CNN size, but nothing works.
about data
86(label: 0) + 63(label: 1) images
shape: (128, 128)
about current parameters
learning_rate = 0.00005(I have tried from 0.00000001 to 0.8...)
batch size = 30(I also have tried from 5 to 130)
epoch = 20
about network
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev = 0.1, dtype = tf.float32)
return tf.Variable(initial)
def bias_variable(shape):
initial = tf.constant(0.1, shape = shape, dtype = tf.float32)
return tf.Variable(initial)
def conv2d(x, W):
#(input, filter, strides, padding)
#[batch, height, width, in_channels]
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
def max_pool_2x2(x):
#(value, ksize, strides, padding)
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
def cnn_model():
epochs = 20
batch_size = 30
learning_rate = 0.00005
hidden = 2
cap_c = 86
cap_h = 63
num = cap_c + cap_h
image_size = 128
label_size = 2
print ((num//(batch_size)) * epochs)
train_loss = np.empty((num//(batch_size)) * epochs)
train_acc = np.empty((num//(batch_size)) * epochs)
x = tf.placeholder(tf.float32, shape = [None, image_size, image_size])
y = tf.placeholder(tf.float32, shape = [None, label_size])
weight_balance = tf.constant([0.1])
X_train_ = tf.reshape(x, [-1, image_size, image_size, 1])
#First layer
W_conv1 = weight_variable([5, 5, 1, 4])
b_conv1 = bias_variable([4])
h_conv1 = tf.nn.relu(conv2d(X_train_, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
# #Second layer
# W_conv2 = weight_variable([5, 5, 4, 8])
# b_conv2 = bias_variable([8])
#
# h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
# h_pool2 = max_pool_2x2(h_conv2)
#
# Third layer
# W_conv3 = weight_variable([5, 5, 8, 16])
# b_conv3 = bias_variable([16])
#
# h_conv3 = tf.nn.relu(conv2d(h_pool2, W_conv3) + b_conv3)
# h_pool3 = max_pool_2x2(h_conv3)
#Full connect layer
W_fc1 = weight_variable([64 * 64 * 4, hidden])
b_fc1 = bias_variable([hidden])
h_pool2_flat = tf.reshape(h_pool1, [-1, 64 * 64 * 4])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
#Output_Softmax
W_fc2 = weight_variable([hidden, label_size])
b_fc2 = bias_variable([label_size])
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
print y_conv.shape
#Train
loss = tf.reduce_mean(tf.nn.weighted_cross_entropy_with_logits(y, y_conv, weight_balance))
optimize = tf.train.AdamOptimizer(learning_rate).minimize(loss)
correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
about result
The loss is not convergent and also the accuracy.
I don't know if my CNN model is not suitable for my data?
or
The Activate function and loss function of the network is not suitable?
Really thank you
There are couple of problems with the code:
You are applying softmax on the last layer and then calling tf.nn.weighted_cross_entropy_with_logits which in turn applies sigmoid activation, so you are applying activation twice.
For initialisation of the weights, use Xavier or Variance_scaling for faster convergence. Better to use tf.layers API in implementing your model as its default settings follows best practices.

Dynamic image cropping in Tensorflow

I'm trying to figure out how to take a crop of an image determined dynamically in Tensorflow. Below is an example of what I am trying to accomplish, however I can't seem to make it work. Essentially, I want to feed images and the crop values for that image within the graph, and then continue on with other computations on those cropped pieces. My current attempt:
import tensorflow as tf
from matplotlib import pyplot as plt
import numpy as np
sess = tf.InteractiveSession()
img1 = np.random.random([400, 600, 3])
img2 = np.random.random([400, 600, 3])
img3 = np.random.random([400, 600, 3])
images = [img1, img2, img3]
img1_crop = [100, 100, 100, 100]
img2_crop = [200, 150, 100, 100]
img3_crop = [150, 200, 100, 100]
crop_values = [img1_crop, img2_crop, img3_crop]
def crop_image(img, crop):
tf.image.crop_to_bounding_box(img,
crop[0],
crop[1],
crop[2],
crop[3])
image_placeholder = tf.placeholder("float", [None, 400, 600, 3])
crop_placeholder = tf.placeholder(dtype=tf.int32)
sess.run(tf.global_variables_initializer())
cropped_image = tf.map_fn(lambda img, crop: crop_image(img, crop), elems=[image_placeholder, crop_placeholder])
result = sess.run(cropped_image, feed_dict={image_placeholder: images, crop_placeholder:crop_values})
plt.imshow(result)
plt.show()
/Users/p111/anaconda/bin/python /Users/p111/PycharmProjects/analysis_code/testing.py
Traceback (most recent call last):
File "/Users/p111/PycharmProjects/analysis_code/testing.py", line 31, in
cropped_image = tf.map_fn(lambda img, crop: crop_image(img, crop), elems=[image_placeholder, crop_placeholder])
File "/Users/p111/anaconda/lib/python3.5/site-packages/tensorflow/python/ops/functional_ops.py", line 390, in map_fn
swap_memory=swap_memory)
File "/Users/p111/anaconda/lib/python3.5/site-packages/tensorflow/python/ops/control_flow_ops.py", line 2636, in while_loop
result = context.BuildLoop(cond, body, loop_vars, shape_invariants)
File "/Users/p111/anaconda/lib/python3.5/site-packages/tensorflow/python/ops/control_flow_ops.py", line 2469, in BuildLoop
pred, body, original_loop_vars, loop_vars, shape_invariants)
File "/Users/p111/anaconda/lib/python3.5/site-packages/tensorflow/python/ops/control_flow_ops.py", line 2419, in _BuildLoop
body_result = body(*packed_vars_for_body)
File "/Users/p111/anaconda/lib/python3.5/site-packages/tensorflow/python/ops/functional_ops.py", line 380, in compute
packed_fn_values = fn(packed_values)
TypeError: () missing 1 required positional argument: 'crop'
Edit: It appears that elems will only accept a single tensor. Which means I would need to somehow combine my two tensors into one, and then unpack it in my function to get the values out. I'm not sure how I would perform that kind of tensor manipulation. I have found the glimpse method already and that does work, however I am wondering if the same can be done with this specific method. Mostly, I'm wondering how you would combine and then split a pair of tensors so it can be used in this method.
I saw this code from here.
elems = (np.array([1, 2, 3]), np.array([-1, 1, -1]))
alternate = map_fn(lambda x: x[0] * x[1], elems, dtype=tf.int64)
# alternate == [-1, 2, -3]
It is possible to use a tuple or a list to pack several elements into one so I tried this.
import tensorflow as tf
from matplotlib import pyplot as plt
import numpy as np
sess = tf.InteractiveSession()
img1 = np.random.random([400, 600, 3])
img2 = np.random.random([400, 600, 3])
img3 = np.random.random([400, 600, 3])
images = np.array([img1, img2, img3])
# images = tf.convert_to_tensor(images) # it can be uncommented.
img1_crop = [100, 100, 100, 100]
img2_crop = [200, 150, 100, 100]
img3_crop = [150, 200, 100, 100]
crop_values = np.array([img1_crop, img2_crop, img3_crop])
# crop_values = tf.convert_to_tensor(crop_values) # it can be uncommented.
def crop_image(img, crop):
return tf.image.crop_to_bounding_box(img,
crop[0],
crop[1],
crop[2],
crop[3])
fn = lambda x: crop_image(x[0], x[1])
elems = (images, crop_values)
cropped_image = tf.map_fn(fn, elems=elems, dtype=tf.float64)
result = sess.run(cropped_image)
print result.shape
plt.imshow(result[0])
plt.show()
It works on my machine with tf version 0.11 and python2. Hope this can help you.
Couple of things :
You do not have a return statement in the crop_image function.
map_fn accepts a single argument.
I strongly advise you to separate the graph definition and the session usage.
--
# Graph def
def crop_image(img, crop):
return tf.image.crop_to_bounding_box(img,
crop[0],
crop[1],
crop[2],
crop[3])
image_placeholder = tf.placeholder(tf.float32, [None, 400, 600, 3])
crop_placeholder = tf.placeholder(dtype=tf.int32)
cropped_image = tf.map_fn(lambda inputs: crop_image(*inputs), elems=[image_placeholder, crop_placeholder], dtype=tf.float32)
# Session
sess = tf.InteractiveSession()
img1 = np.random.random([400, 600, 3])
img2 = np.random.random([400, 600, 3])
img3 = np.random.random([400, 600, 3])
images = [img1, img2, img3]
img1_crop = [100, 100, 100, 100]
img2_crop = [200, 150, 100, 100]
img3_crop = [150, 200, 100, 100]
crop_values = [img1_crop, img2_crop, img3_crop]
sess.run(tf.global_variables_initializer())
result = sess.run(cropped_image, feed_dict={image_placeholder: images, crop_placeholder:crop_values})
plt.imshow(result[0])
plt.show()
tf.map_fn(f, l) runs function f for every tensor in list l. In your case, your function expects 2 arguments, but since you supply a flat list, map_fn() sends them one by one. According to docs, map_fn() supports variable arity, so what you should do is something like this
tf.map_fn(lambda img, crop: crop_image(img, crop),
elems=([image_placeholder, crop_placeholder], ))
so the list you pass to map_fn contains pairs of arguments.

Resources