Categories
Offsites

Forecasting El Niño-Southern Oscillation (ENSO)

Today, we use the convLSTM introduced in a previous post to predict El Niño-Southern Oscillation (ENSO).

El Niño, la Niña

ENSO refers to a changing pattern of sea surface temperatures and sea-level pressures occurring in the equatorial Pacific. From its three overall states, probably the best-known is El Niño. El Niño occurs when surface water temperatures in the eastern Pacific are higher than normal, and the strong winds that normally blow from east to west are unusually weak. The opposite conditions are termed La Niña. Everything in-between is classified as normal.

ENSO has great impact on the weather worldwide, and routinely harms ecosystems and societies through storms, droughts and flooding, possibly resulting in famines and economic crises. The best societies can do is try to adapt and mitigate severe consequences. Such efforts are aided by accurate forecasts, the further ahead the better.

Here, deep learning (DL) can potentially help: Variables like sea surface temperatures and pressures are given on a spatial grid – that of the earth – and as we know, DL is good at extracting spatial (e.g., image) features. For ENSO prediction, architectures like convolutional neural networks (Ham, Kim, and Luo (2019)) or convolutional-recurrent hybrids1 are habitually used. One such hybrid is just our convLSTM; it operates on sequences of features given on a spatial grid. Today, thus, we’ll be training a model for ENSO forecasting. This model will have a convLSTM for its central ingredient.

Before we start, a note. While our model fits well with architectures described in the relevant papers, the same cannot be said for amount of training data used. For reasons of practicality, we use actual observations only; consequently, we end up with a small (relative to the task) dataset. In contrast, research papers tend to make use of climate simulations2, resulting in significantly more data to work with.

From the outset, then, we don’t expect stellar performance. Nevertheless, this should make for an interesting case study, and a useful code template for our readers to apply to their own data.

Data

We will attempt to predict monthly average sea surface temperature in the Niño 3.4 region3, as represented by the Niño 3.4 Index, plus categorization as one of El Niño, La Niña or neutral4. Predictions will be based on prior monthly sea surface temperatures spanning a large portion of the globe.

On the input side, public and ready-to-use data may be downloaded from Tokyo Climate Center; as to prediction targets, we obtain index and classification here.

Input and target data both are provided monthly. They intersect in the time period ranging from 1891-01-01 to 2020-08-01; so this is the range of dates we’ll be zooming in on.

Input: Sea Surface Temperatures

Monthly sea surface temperatures are provided in a latitude-longitude grid of resolution 1°. Details of how the data were processed are available here.

Data files are available in GRIB format; each file contains averages computed for a single month. We can either download individual files or generate a text file of URLs for download. In case you’d like to follow along with the post, you’ll find the contents of the text file I generated in the appendix. Once you’ve saved these URLs to a file, you can have R get the files for you like so:

purrr::walk(
   readLines("files"),
   function(f) download.file(url = f, destfile = basename(f))
)

From R, we can read GRIB files using stars. For example:

# let's just quickly load all libraries we require to start with

library(torch)
library(tidyverse)
library(stars)
library(viridis)
library(ggthemes)

torch_manual_seed(777)

read_stars(file.path(grb_dir, "sst189101.grb"))
stars object with 2 dimensions and 1 attribute
attribute(s):
 sst189101.grb   
 Min.   :-274.9  
 1st Qu.:-272.8  
 Median :-259.1  
 Mean   :-260.0  
 3rd Qu.:-248.4  
 Max.   :-242.8  
 NA's   :21001   
dimension(s):
  from  to offset delta                       refsys point values    
x    1 360      0     1 Coordinate System importe...    NA   NULL [x]
y    1 180     90    -1 Coordinate System importe...    NA   NULL [y]

So in this GRIB file, we have one attribute – which we know to be sea surface temperature – on a two-dimensional grid. As to the latter, we can complement what stars tells us with additional info found in the documentation:

The east-west grid points run eastward from 0.5ºE to 0.5ºW, while the north-south grid points run northward from 89.5ºS to 89.5ºN.

We note a few things we’ll want to do with this data. For one, the temperatures seem to be given in Kelvin, but with minus signs.5 We’ll remove the minus signs and convert to degrees Celsius for convenience. We’ll also have to think about what to do with the NAs that appear for all non-maritime coordinates.

Before we get there though, we need to combine data from all files into a single data frame. This adds an additional dimension, time, ranging from 1891/01/01 to 2020/01/12:

grb <- read_stars(
  file.path(grb_dir, map(readLines("files", warn = FALSE), basename)), along = "time") %>%
  st_set_dimensions(3,
                    values = seq(as.Date("1891-01-01"), as.Date("2020-12-01"), by = "months"),
                    names = "time"
                    )

grb
stars object with 3 dimensions and 1 attribute
attribute(s), summary of first 1e+05 cells:
 sst189101.grb   
 Min.   :-274.9  
 1st Qu.:-273.3  
 Median :-258.8  
 Mean   :-260.0  
 3rd Qu.:-247.8  
 Max.   :-242.8  
 NA's   :33724   
dimension(s):
     from   to offset delta                       refsys point                    values    
x       1  360      0     1 Coordinate System importe...    NA                      NULL [x]
y       1  180     90    -1 Coordinate System importe...    NA                      NULL [y]
time    1 1560     NA    NA                         Date    NA 1891-01-01,...,2020-12-01    

Let’s visually inspect the spatial distribution of monthly temperatures for one year, 2020:

ggplot() +
  geom_stars(data = grb %>% filter(between(time, as.Date("2020-01-01"), as.Date("2020-12-01"))), alpha = 0.8) +
  facet_wrap("time") +
  scale_fill_viridis() +
  coord_equal() +
  theme_map() +
  theme(legend.position = "none") 
Monthly sea surface temperatures, 2020/01/01 - 2020/01/12.

(#fig:unnamed-chunk-5)Monthly sea surface temperatures, 2020/01/01 – 2020/01/12.

Target: Niño 3.4 Index

For the Niño 3.4 Index, we download the monthly data and, among the provided features, zoom in on two: the index itself (column NINO34_MEAN) and PHASE, which can be E (El Niño), L (La Niño) or N (neutral).

nino <- read_table2("ONI_NINO34_1854-2020.txt", skip = 9) %>%
  mutate(month = as.Date(paste0(YEAR, "-", `MON/MMM`, "-01"))) %>%
  select(month, NINO34_MEAN, PHASE) %>%
  filter(between(month, as.Date("1891-01-01"), as.Date("2020-08-01"))) %>%
  mutate(phase_code = as.numeric(as.factor(PHASE)))

nrow(nino)
1556

Next, we look at how to get the data into a format convenient for training and prediction.

Preprocessing Input

First, we remove all input data for points in time where ground truth data are still missing.

sst <- grb %>% filter(time <= as.Date("2020-08-01"))

Next, as is done by e.g. Ham, Kim, and Luo (2019), we only use grid points between 55° south and 60° north. This has the additional advantage of reducing memory requirements.

sst <- grb %>% filter(between(y,-55, 60))

dim(sst)
360, 115, 1560

As already alluded to, with the little data we have we can’t expect much in terms of generalization. Still, we set aside a small portion of the data for validation, since we’d like for this post to serve as a useful template to be used with bigger datasets.

sst_train <- sst %>% filter(time < as.Date("1990-01-01"))
sst_valid <- sst %>% filter(time >= as.Date("1990-01-01"))

From here on, we work with R arrays.

sst_train <- as.tbl_cube.stars(sst_train)$mets[[1]]
sst_valid <- as.tbl_cube.stars(sst_valid)$mets[[1]]

Conversion to degrees Celsius is not strictly necessary, as initial experiments showed a slight performance increase due to normalizing the input, and we’re going to do that anyway. Still, it reads nicer to humans than Kelvin.

sst_train <- sst_train + 273.15
quantile(sst_train, na.rm = TRUE)
     0%     25%     50%     75%    100% 
-1.8000 12.9975 21.8775 26.8200 34.3700 

Not at all surprisingly, global warming is evident from inspecting temperature distribution on the validation set (which was chosen to span the last thirty-one years).

sst_valid <- sst_valid + 273.15
quantile(sst_valid, na.rm = TRUE)
    0%    25%    50%    75%   100% 
-1.800 13.425 22.335 27.240 34.870 

The next-to-last step normalizes both sets according to training mean and variance.

train_mean <- mean(sst_train, na.rm = TRUE)
train_sd <- sd(sst_train, na.rm = TRUE)

sst_train <- (sst_train - train_mean) / train_sd

sst_valid <- (sst_valid - train_mean) / train_sd

Finally, what should we do about the NA entries? We set them to zero, the (training set) mean. That may not be enough of an action though: It means we’re feeding the network roughly 30% misleading data. This is something we’re not done with yet.

sst_train[is.na(sst_train)] <- 0
sst_valid[is.na(sst_valid)] <- 0

Target

The target data are split analogously. Let’s check though: Are phases (categorizations) distributedly similarly in both sets?

nino_train <- nino %>% filter(month < as.Date("1990-01-01"))
nino_valid <- nino %>% filter(month >= as.Date("1990-01-01"))

nino_train %>% group_by(phase_code, PHASE) %>% summarise(count = n(), avg = mean(NINO34_MEAN))
# A tibble: 3 x 4
# Groups:   phase_code [3]
  phase_code PHASE count   avg
       <dbl> <chr> <int> <dbl>
1          1 E       301  27.7
2          2 L       333  25.6
3          3 N       554  26.7
nino_valid %>% group_by(phase_code, PHASE) %>% summarise(count = n(), avg = mean(NINO34_MEAN))
# A tibble: 3 x 4
# Groups:   phase_code [3]
  phase_code PHASE count   avg
       <dbl> <chr> <int> <dbl>
1          1 E        93  28.1
2          2 L        93  25.9
3          3 N       182  27.2

This doesn’t look too bad. Of course, we again see the overall rise in temperature, irrespective of phase.

Lastly, we normalize the index, same as we did for the input data.

train_mean_nino <- mean(nino_train$NINO34_MEAN)
train_sd_nino <- sd(nino_train$NINO34_MEAN)

nino_train <- nino_train %>% mutate(NINO34_MEAN = scale(NINO34_MEAN, center = train_mean_nino, scale = train_sd_nino))
nino_valid <- nino_valid %>% mutate(NINO34_MEAN = scale(NINO34_MEAN, center = train_mean_nino, scale = train_sd_nino))

On to the torch dataset.

Torch dataset

The dataset is responsible for correctly matching up inputs and targets.

Our goal is to take six months of global sea surface temperatures and predict the Niño 3.4 Index for the following month. Input-wise, the model will expect the following format semantics:

batch_size * timesteps * width * height * channels, where

  • batch_size is the number of observations worked on in one round of computations,

  • timesteps chains consecutive observations from adjacent months,

  • width and height together constitute the spatial grid, and

  • channels corresponds to available visual channels in the “image”.

In .getitem(), we select the consecutive observations, starting at a given index, and stack them in dimension one. (One, not two, as batches will only start to exist once the dataloader comes into play.)

Now, what about the target? Our ultimate goal was – is – predicting the Niño 3.4 Index. However, as you see we define three targets: One is the index, as expected; an additional one holds the spatially-gridded sea surface temperatures for the prediction month. Why? Our main instrument, the most prominent constituent of the model, will be a convLSTM, an architecture designed for spatial prediction. Thus, to train it efficiently, we want to give it the opportunity to predict values on a spatial grid. So far so good; but there’s one more target, the phase/category. This was added for experimentation purposes: Maybe predicting both index and phase helps in training?

Finally, here is the code for the dataset. In our experiments, we based predictions on inputs from the preceding six months (n_timesteps <- 6). This is a parameter you might want to play with, though.

n_timesteps <- 6

enso_dataset <- dataset(
  name = "enso_dataset",
  
  initialize = function(sst, nino, n_timesteps) {
    self$sst <- sst
    self$nino <- nino
    self$n_timesteps <- n_timesteps
  },
  
  .getitem = function(i) {
    x <- torch_tensor(self$sst[, , i:(n_timesteps + i - 1)]) # (360, 115, n_timesteps)
    x <- x$permute(c(3,1,2))$unsqueeze(2) # (n_timesteps, 1, 360, 115))
    
    y1 <- torch_tensor(self$sst[, , n_timesteps + i])$unsqueeze(1) # (1, 360, 115)
    y2 <- torch_tensor(self$nino$NINO34_MEAN[n_timesteps + i])
    y3 <- torch_tensor(self$nino$phase_code[n_timesteps + i])$squeeze()$to(torch_long())
    list(x = x, y1 = y1, y2 = y2, y3 = y3)
  },
  
  .length = function() {
    nrow(self$nino) - n_timesteps
  }
  
)

valid_ds <- enso_dataset(sst_valid, nino_valid, n_timesteps)

Dataloaders

After the custom dataset, we create the – pretty typical – dataloaders, making use of a batch size of 4.

batch_size <- 4

train_dl <- train_ds %>% dataloader(batch_size = batch_size, shuffle = TRUE)

valid_dl <- valid_ds %>% dataloader(batch_size = batch_size)

Next, we proceed to model creation.

Model

The model’s main ingredient is the convLSTM introduced in a prior post. For convenience, we reproduce the code in the appendix.

Besides the convLSTM, the model makes use of three convolutional layers, a batchnorm layer and five linear layers. The logic is the following.

First, the convLSTM job is to predict the next month’s sea surface temperatures on the spatial grid. For that, we almost just return its final state, – almost: We use self$conv1 to reduce the number channels to one.

For predicting index and phase, we then need to flatten the grid, as we require a single value each. This is where the additional conv layers come in. We do hope they’ll aid in learning, but we also want to reduce the number of parameters a bit, downsizing the grid (strides = 2 and strides = 3, resp.) a bit before the upcoming torch_flatten().

Once we have a flat structure, learning is shared between the tasks of index and phase prediction (self$linear), until finally their paths split (self$cont and self$cat, resp.), and they return their separate outputs.

(The batchnorm? I’ll comment on that in the Discussion.)

model <- nn_module(
  
  initialize = function(channels_in,
                        convlstm_hidden,
                        convlstm_kernel,
                        convlstm_layers) {
    
    self$n_layers <- convlstm_layers
    
    self$convlstm <- convlstm(
      input_dim = channels_in,
      hidden_dims = convlstm_hidden,
      kernel_sizes = convlstm_kernel,
      n_layers = convlstm_layers
    )
    
    self$conv1 <-
      nn_conv2d(
        in_channels = 32,
        out_channels = 1,
        kernel_size = 5,
        padding = 2
      )
    
    self$conv2 <-
      nn_conv2d(
        in_channels = 32,
        out_channels = 32,
        kernel_size = 5,
        stride = 2
      )
    
    self$conv3 <-
      nn_conv2d(
        in_channels = 32,
        out_channels = 32,
        kernel_size = 5,
        stride = 3
      )
    
    self$linear <- nn_linear(33408, 64)
    
    self$b1 <- nn_batch_norm1d(num_features = 64)
        
    self$cont <- nn_linear(64, 128)
    self$cat <- nn_linear(64, 128)
    
    self$cont_output <- nn_linear(128, 1)
    self$cat_output <- nn_linear(128, 3)
    
  },
  
  forward = function(x) {
    
    ret <- self$convlstm(x)
    layer_last_states <- ret[[2]]
    last_hidden <- layer_last_states[[self$n_layers]][[1]]
    
    next_sst <- last_hidden %>% self$conv1() 
    
    c2 <- last_hidden %>% self$conv2() 
    c3 <- c2 %>% self$conv3() 
    
    flat <- torch_flatten(c3, start_dim = 2)
    common <- self$linear(flat) %>% self$b3() %>% nnf_relu()

    next_temp <- common %>% self$cont() %>% nnf_relu() %>% self$cont_output()
    next_nino <- common %>% self$cat() %>% nnf_relu() %>% self$cat_output()
    
    list(next_sst, next_temp, next_nino)
    
  }
  
)

Next, we instantiate a pretty small-ish model. You’re more than welcome to experiment with larger models, but training time as well as GPU memory requirements will increase.

net <- model(
  channels_in = 1,
  convlstm_hidden = c(16, 16, 32),
  convlstm_kernel = c(3, 3, 5),
  convlstm_layers = 3
)

device <- torch_device(if (cuda_is_available()) "cuda" else "cpu")

net <- net$to(device = device)
net
An `nn_module` containing 2,389,605 parameters.

── Modules ───────────────────────────────────────────────────────────────────────────────
● convlstm: <nn_module> #182,080 parameters
● conv1: <nn_conv2d> #801 parameters
● conv2: <nn_conv2d> #25,632 parameters
● conv3: <nn_conv2d> #25,632 parameters
● linear: <nn_linear> #2,138,176 parameters
● b1: <nn_batch_norm1d> #128 parameters
● cont: <nn_linear> #8,320 parameters
● cat: <nn_linear> #8,320 parameters
● cont_output: <nn_linear> #129 parameters
● cat_output: <nn_linear> #387 parameters

Training

We have three model outputs. How should we combine the losses?

Given that the main goal is predicting the index, and the other two outputs are essentially means to an end, I found the following combination rather effective:

# weight for sea surface temperature prediction
lw_sst <- 0.2

# weight for prediction of El Nino 3.4 Index
lw_temp <- 0.4

# weight for phase prediction
lw_nino <- 0.4

The training process follows the pattern seen in all torch posts so far: For each epoch, loop over the training set, backpropagate, check performance on validation set.

But, when we did the pre-processing, we were aware of an imminent problem: the missing temperatures for continental areas, which we set to zero. As a sole measure, this approach is clearly insufficient. What if we had chosen to use latitude-dependent averages? Or interpolation? Both may be better than a global average, but both have their problems as well. Let’s at least alleviate negative consequences by not using the respective pixels for spatial loss calculation. This is taken care of by the following line below:

sst_loss <- nnf_mse_loss(sst_output[sst_target != 0], sst_target[sst_target != 0])

Here, then, is the complete training code.

optimizer <- optim_adam(net$parameters, lr = 0.001)

num_epochs <- 50

train_batch <- function(b) {
  
  optimizer$zero_grad()
  output <- net(b$x$to(device = device))
  
  sst_output <- output[[1]]
  sst_target <- b$y1$to(device = device)
  
  sst_loss <- nnf_mse_loss(sst_output[sst_target != 0], sst_target[sst_target != 0])
  temp_loss <- nnf_mse_loss(output[[2]], b$y2$to(device = device))
  nino_loss <- nnf_cross_entropy(output[[3]], b$y3$to(device = device))
  
  loss <- lw_sst * sst_loss + lw_temp * temp_loss + lw_nino * nino_loss
  loss$backward()
  optimizer$step()

  list(sst_loss$item(), temp_loss$item(), nino_loss$item(), loss$item())
  
}

valid_batch <- function(b) {
  
  output <- net(b$x$to(device = device))
  
  sst_output <- output[[1]]
  sst_target <- b$y1$to(device = device)
  
  sst_loss <- nnf_mse_loss(sst_output[sst_target != 0], sst_target[sst_target != 0])
  temp_loss <- nnf_mse_loss(output[[2]], b$y2$to(device = device))
  nino_loss <- nnf_cross_entropy(output[[3]], b$y3$to(device = device))
  
  loss <-
    lw_sst * sst_loss + lw_temp * temp_loss + lw_nino * nino_loss

  list(sst_loss$item(),
       temp_loss$item(),
       nino_loss$item(),
       loss$item())
}

for (epoch in 1:num_epochs) {
  
  net$train()
  
  train_loss_sst <- c()
  train_loss_temp <- c()
  train_loss_nino <- c()
  train_loss <- c()

  coro::loop(for (b in train_dl) {
    losses <- train_batch(b)
    train_loss_sst <- c(train_loss_sst, losses[[1]])
    train_loss_temp <- c(train_loss_temp, losses[[2]])
    train_loss_nino <- c(train_loss_nino, losses[[3]])
    train_loss <- c(train_loss, losses[[4]])
  })
  
  cat(
    sprintf(
      "nEpoch %d, training: loss: %3.3f sst: %3.3f temp: %3.3f nino: %3.3f n",
      epoch, mean(train_loss), mean(train_loss_sst), mean(train_loss_temp), mean(train_loss_nino)
    )
  )
  
  net$eval()
  
  valid_loss_sst <- c()
  valid_loss_temp <- c()
  valid_loss_nino <- c()
  valid_loss <- c()

  coro::loop(for (b in valid_dl) {
    losses <- valid_batch(b)
    valid_loss_sst <- c(valid_loss_sst, losses[[1]])
    valid_loss_temp <- c(valid_loss_temp, losses[[2]])
    valid_loss_nino <- c(valid_loss_nino, losses[[3]])
    valid_loss <- c(valid_loss, losses[[4]])
    
  })
  
  cat(
    sprintf(
      "nEpoch %d, validation: loss: %3.3f sst: %3.3f temp: %3.3f nino: %3.3f n",
      epoch, mean(valid_loss), mean(valid_loss_sst), mean(valid_loss_temp), mean(valid_loss_nino)
    )
  )
  
  torch_save(net, paste0(
    "model_", epoch, "_", round(mean(train_loss), 3), "_", round(mean(valid_loss), 3), ".pt"
  ))
  
}

When I ran this, performance on the training set decreased in a not-too-fast, but continuous way, while validation set performance kept fluctuating. For reference, total (composite) losses looked like this:

Epoch     Training    Validation
   
   10        0.336         0.633
   20        0.233         0.295
   30        0.135         0.461
   40        0.099         0.903
   50        0.061         0.727

Thinking of the size of the validation set – thirty-one years, or equivalently, 372 data points – those fluctuations may not be all too surprising.

Predictions

Now losses tend to be abstract; let’s see what actually gets predicted. We obtain predictions for index values and phases like so …

net$eval()

pred_index <- c()
pred_phase <- c()

coro::loop(for (b in valid_dl) {

  output <- net(b$x$to(device = device))

  pred_index <- c(pred_index, output[[2]]$to(device = "cpu"))
  pred_phase <- rbind(pred_phase, as.matrix(output[[3]]$to(device = "cpu")))

})

… and combine these with the ground truth, stripping off the first..

Categories
Misc

Simple custom model with custom tf.data.Dataset does not work

I am trying to create a basic, custom model together with a custom tf.data.Dataset. However, running my code gives me a “InvalidArgumentError”.

The full error message:

InvalidArgumentError: Matrix size-incompatible: In[0]: [26,599], In[1]: [15574,2048] [Op:MatMul] 

So I have a signal on which I do a certain calculation. This gives me a 2D matrix of 26 rows and 599 columns. I want to group these matrices in a tf.data.Dataset, so that I can use them later to build a model.

The full code and error message are given below. TensorFlow version is 2.3.1.

Could someone please help me identify the issue?

Thanks in advance.

Dataset creation (tf.data.Dataset)

""" Create separate tf.data.Dataset's for the training and test set. """ # Create train labels signal_matrices_train = signal_matrices.get_xval_set(fold=0, set='train') matrices_list = [] label1_list = [] label2_list = [] for i in range(len(signal_matrices_train)): matrices_list.append(signal_matrices_train[i]['preprocessed']['matrix']) label1_list.append(signal_matrices_train[i]['label1'] label2_list.append(signal_matrices_train[i]['label2']) train_array = np.dstack(matrices_list) train_array = np.swapaxes(train_array, 1, 0) # To get (26, 599) for the signal matrices train_label1_array = np.array(label1_list) train_label2_array = np.array(label2_list) if(train_label1_array.shape == train_label2_array.shape): temparr = np.column_stack((train_label1_array, train_label2_array)) train_dataset_tf = tf.data.Dataset.from_tensor_slices((train_array.T, temparr)) else: print('Train: Label1 and label2 array do not have same length.') train_dataset_tf = tf.data.Dataset.from_tensor_slices((train_array.T, train_label1_array, train_label2_array)) # Same for test labels 

After the dataset declarations, I try to check if things are as I would expect:

""" Print info about train_dataset_tf """ print('Training dataset:') pprint(train_dataset_tf.element_spec) print('Length of train_dataset_tf: ', len(train_dataset_tf)) print('nTest dataset:') pprint(test_dataset_tf.element_spec) print('Length of test_dataset_tf: ', len(test_dataset_tf)) Output: Training dataset: (TensorSpec(shape=(26, 599), dtype=tf.float64, name=None), TensorSpec(shape=(2,), dtype=tf.int64, name=None)) Length of train_dataset_tf: 2351 Test dataset: (TensorSpec(shape=(26, 599), dtype=tf.float64, name=None), TensorSpec(shape=(2,), dtype=tf.int64, name=None)) Length of test_dataset_tf: 1541 

I indeed have matrices of [26×599] containing floats and I have two binary classes (one-hot encoded).

Next, I print the first element of the training dataset:

""" Give an example of an element in the training dataset """ it = iter(train_dataset_tf) print(next(it)) Output: (<tf.Tensor: shape=(26, 599), dtype=float64, numpy= array([[ 0.0072, 0.0100 , 0.0108, ..., 0.0097, 0.0070, 0.0091 ], [ 0.0070, 0.0092, 0.0099, ..., 0.0090, 0.0069, 0.0085 ], [ 0.0029 , 0.0041, 0.0044, ..., 0.0039, 0.0030, 0.0040], ..., [-0.0047, -0.0049, -0.0047, ..., -0.0054, -0.0057, -0.0047], [-0.0045, -0.0050 , -0.0049, ..., -0.0056, -0.0057, -0.0046], [-0.0042, -0.0049, -0.0047, ..., -0.0056, -0.0059, -0.0043]])>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([0, 1])>) 

The last step of the dataset creation is to generate batches with a size of 32:

""" Create batches of training data """ train_batches = train_dataset_tf.shuffle(5000, seed=17, reshuffle_each_iteration=True).batch(BATCH_SIZE, drop_remainder=True) # Buffer size = 5000 and batch size = 32 (buffer size greater or equal to dataset size is recommended) 

Model creation

""" Model declaration """ # Source: https://www.tensorflow.org/tutorials/keras/classification#preprocess_the_data model = Sequential() model.add(Input(shape=[26,599], batch_size=BATCH_SIZE, name='input')) model.add(Flatten(input_shape=[26, 599], data_format=None, name='flatten1')) # Go from 2D [26x599] to 1D [15 574] model.add(Dense(2048, activation='relu', name='dense1', input_shape=[15574])) model.add(Dense(512, activation='relu', name='dense2')) model.add(Dense(128, activation='relu', name='dense3')) model.add(Dense(NUM_CLASSES, activation='sigmoid', name='dense_classification')) # Output layer that does classification model.compile('sgd', 'binary_crossentropy', metrics=['accuracy']) 

Next, I try to check if the model declaration is correct. I do this with model.summary():

model.summary() Output: Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= flatten1 (Flatten) (32, 15574) 0 _________________________________________________________________ dense1 (Dense) (32, 2048) 31897600 _________________________________________________________________ dense2 (Dense) (32, 512) 1049088 _________________________________________________________________ dense3 (Dense) (32, 128) 65664 _________________________________________________________________ dense_classification (Dense) (32, 2) 258 ================================================================= Total params: 33,012,610 Trainable params: 33,012,610 Non-trainable params: 0 

In my eyes, this seems to be correct.

The final step is to train the model. This part also contains the full error message that is thrown:

# Definition of callbacks reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=5, min_lr=0, mode='auto', verbose=1) early_stop = EarlyStopping(monitor='val_loss', min_delta=0.0001, patience=14, verbose=0, mode='auto', restore_best_weights=True) csv_logger = CSVLogger(LOGFILE, separator=',', append=True) # Train the model history = model.fit( train_dataset_tf, batch_size=BATCH_SIZE, epochs=5, verbose=2, callbacks = [reduce_lr, csv_logger, early_stop], shuffle=True ) Output: Epoch 1/5 --------------------------------------------------------------------------- InvalidArgumentError Traceback (most recent call last) <ipython-input-39-9d9a4ccaf472> in <module> 35 callbacks = [reduce_lr, csv_logger, early_stop], 36 class_weight = CLASS_WEIGHTS, ---> 37 shuffle=True 38 ) ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py in _method_wrapper(self, *args, **kwargs) 106 def _method_wrapper(self, *args, **kwargs): 107 if not self._in_multi_worker_mode(): # pylint: disable=protected-access --> 108 return method(self, *args, **kwargs) 109 110 # Running inside `run_distribute_coordinator` already. ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_batch_size, validation_freq, max_queue_size, workers, use_multiprocessing) 1096 batch_size=batch_size): 1097 callbacks.on_train_batch_begin(step) -> 1098 tmp_logs = train_function(iterator) 1099 if data_handler.should_sync: 1100 context.async_wait() ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py in train_function(iterator) 804 def train_function(iterator): 805 """Runs a training execution with one step.""" --> 806 return step_function(self, iterator) 807 808 else: ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py in step_function(model, iterator) 794 795 data = next(iterator) --> 796 outputs = model.distribute_strategy.run(run_step, args=(data,)) 797 outputs = reduce_per_replica( 798 outputs, self.distribute_strategy, reduction='first') ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/distribute/distribute_lib.py in run(***failed resolving arguments***) 1209 fn = autograph.tf_convert( 1210 fn, autograph_ctx.control_status_ctx(), convert_by_default=False) -> 1211 return self._extended.call_for_each_replica(fn, args=args, kwargs=kwargs) 1212 1213 # TODO(b/151224785): Remove deprecated alias. ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/distribute/distribute_lib.py in call_for_each_replica(self, fn, args, kwargs) 2583 kwargs = {} 2584 with self._container_strategy().scope(): -> 2585 return self._call_for_each_replica(fn, args, kwargs) 2586 2587 def _call_for_each_replica(self, fn, args, kwargs): ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/distribute/distribute_lib.py in _call_for_each_replica(self, fn, args, kwargs) 2943 self._container_strategy(), 2944 replica_id_in_sync_group=constant_op.constant(0, dtypes.int32)): -> 2945 return fn(*args, **kwargs) 2946 2947 def _reduce_to(self, reduce_op, value, destinations, experimental_hints): ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/autograph/impl/api.py in wrapper(*args, **kwargs) 273 def wrapper(*args, **kwargs): 274 with ag_ctx.ControlStatusCtx(status=ag_ctx.Status.UNSPECIFIED): --> 275 return func(*args, **kwargs) 276 277 if inspect.isfunction(func) or inspect.ismethod(func): ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py in run_step(data) 787 788 def run_step(data): --> 789 outputs = model.train_step(data) 790 # Ensure counter is updated only if `train_step` succeeds. 791 with ops.control_dependencies(_minimum_control_deps(outputs)): ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py in train_step(self, data) 745 746 with backprop.GradientTape() as tape: --> 747 y_pred = self(x, training=True) 748 loss = self.compiled_loss( 749 y, y_pred, sample_weight, regularization_losses=self.losses) ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer.py in __call__(self, *args, **kwargs) 983 984 with ops.enable_auto_cast_variables(self._compute_dtype_object): --> 985 outputs = call_fn(inputs, *args, **kwargs) 986 987 if self._activity_regularizer: ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/engine/sequential.py in call(self, inputs, training, mask) 370 if not self.built: 371 self._init_graph_network(self.inputs, self.outputs) --> 372 return super(Sequential, self).call(inputs, training=training, mask=mask) 373 374 outputs = inputs # handle the corner case where self.layers is empty ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/engine/functional.py in call(self, inputs, training, mask) 384 """ 385 return self._run_internal_graph( --> 386 inputs, training=training, mask=mask) 387 388 def compute_output_shape(self, input_shape): ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/engine/functional.py in _run_internal_graph(self, inputs, training, mask) 506 507 args, kwargs = node.map_arguments(tensor_dict) --> 508 outputs = node.layer(*args, **kwargs) 509 510 # Update tensor_dict. ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer.py in __call__(self, *args, **kwargs) 983 984 with ops.enable_auto_cast_variables(self._compute_dtype_object): --> 985 outputs = call_fn(inputs, *args, **kwargs) 986 987 if self._activity_regularizer: ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/layers/core.py in call(self, inputs) 1196 self.bias, 1197 self.activation, -> 1198 dtype=self._compute_dtype_object) 1199 1200 def compute_output_shape(self, input_shape): ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/keras/layers/ops/core.py in dense(inputs, kernel, bias, activation, dtype) 51 outputs = sparse_ops.sparse_tensor_dense_matmul(inputs, kernel) 52 else: ---> 53 outputs = gen_math_ops.mat_mul(inputs, kernel) 54 # Broadcast kernel to inputs. 55 else: ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/ops/gen_math_ops.py in mat_mul(a, b, transpose_a, transpose_b, name) 5622 return _result 5623 except _core._NotOkStatusException as e: -> 5624 _ops.raise_from_not_ok_status(e, name) 5625 except _core._FallbackException: 5626 pass ~/myvenv/project/lib/python3.6/site-packages/tensorflow/python/framework/ops.py in raise_from_not_ok_status(e, name) 6841 message = e.message + (" name: " + name if name is not None else "") 6842 # pylint: disable=protected-access -> 6843 six.raise_from(core._status_to_exception(e.code, message), None) 6844 # pylint: enable=protected-access 6845 ~/myvenv/project/lib/python3.6/site-packages/six.py in raise_from(value, from_value) InvalidArgumentError: Matrix size-incompatible: In[0]: [26,599], In[1]: [15574,2048] [Op:MatMul] 

submitted by /u/mich2000222
[visit reddit] [comments]

Categories
Misc

Tensorflow.js Graph Object Detection

Im currently building a web-app that uses tensorflow to scan graph data and turn the data into a visualisation, at the minute the app can only detect a small number of objects based on the coco-ssd trained model (Person, phone, bottle) and I’m struggling with 1) finding other tensorflow models that I can implement to improve what can be detected. 2) tensorflow models that can scan for objects and data within a graph and 3) how to add another model into my code without breaking what already works. I’m very new to using tensorflow and machine learning but below is the code for the web-app that requires the tensorflow model.

code snippets on stack overflow

https://stackoverflow.com/questions/66015902/tensorflow-js-graph-object-detection

submitted by /u/Fawcett_C
[visit reddit] [comments]

Categories
Misc

Installing TensorFlow GPU on Windows 10 with compatible CUDA and cuDNN versions can be a cumbersome task. However, there is a little know fact that it can be done by just two commands if we are using Anaconda!! and I hope it equally works for Linux too.

Installing TensorFlow GPU on Windows 10 with compatible CUDA and cuDNN versions can be a cumbersome task. However, there is a little know fact that it can be done by just two commands if we are using Anaconda!! and I hope it equally works for Linux too. submitted by /u/TheCodingBug
[visit reddit] [comments]
Categories
Misc

Some help with dataset from images

Hello guys, I’m a bit new on tensorflow, I’m trying to make a dataset from ONE folder but the only thing I could made is make a dataset with separate folders using flow_from_directory, which will made a dataset in wich each class is a folder, but I want to make it just from one folder, could you please tell me some way in which I can make it?

submitted by /u/engdiazmu
[visit reddit] [comments]

Categories
Misc

bigger Dataset resulting in loss of NaN without exeeding RAM limits

I’m currently trying to build a model that can authenticate a person on their movement data (accelleration etc)

The dataset is built by me and stored in a JSON file for training in google colab. Sample Notebook

Now older versions of the dataset with less worked out fine. But the new version I got has more entries and sudenly I only get a Loss of NaN and Accuracy of 0.5, no matter what I do.

RAM seems to be an obvious reason, but the RAM usage tracker in colab shows normal levels (2-4gb of the available 13) Also I mocked up dummy datasets with the same, or even bigger sizes and they worked out fine.

Do you guys have any Idea what is going on here? My only idea going forward is to move over to TFRecords instead of the JSON file.

submitted by /u/Cha-Dao_Tech
[visit reddit] [comments]

Categories
Misc

Couple Questions about TF Serving

I’ve been reading about TF Serving quite a bit, trying to decide if it makes sense to be using it for some applications that I’m working on. As I’ve been studying up on it , I’ve run into a few things that I can’t seem to answer myself, so I thought I would turn to you beautiful people to see if I could find some answers that I haven’t been able to figure out so far.

1) Trying to build the Docker image in the first place. I read through the documentation on https://www.tensorflow.org/tfx/serving/docker and followed the directions to get my model into a Docker image. However, due to the constraints of what I’m working on, I need to be able to build the container from a Dockerfile in the first place. I found the Dockerfile for TF Serving on Github here: https://github.com/tensorflow/serving/blob/master/tensorflow_serving/tools/docker/Dockerfile.devel But when I build that image, it’s like… 20 times the size of the 300MB one that I get when following the instructions in the docs. I’m looking for a way to have a Dockerfile that I can build into the 300MB image… so that’s one question.

2) My model currently expects an input of a multi dimensional Tensor. With TF Serving using JSON (a requirement to use instead of gRPC on this project… comes from on high and can’t do anything about it), it looks like my options are basically to use something Base64 encoded. Is there a way to circumnavigate this so that I can send a multidimensional Tensor to my model or do I have to rebuild my model so that it can take in a Base64 image? Ideally… I would like to be able to send the file path to the TF Serving Docker and it would pick it up and go from there, but it doesn’t seem like that’s an option. So I suppose the question is… is base64 the only way to get an image to the model using JSON?

Thanks for any answers… I’ve been banging my head on this off and on for the last month and would love any input that you guys can give me!

submitted by /u/TypeAskee
[visit reddit] [comments]

Categories
Misc

Linear Classifier – Training dataset is missing some categorical values which appear in Evaluation dataset. How to handle?

Hi,

I have a training dataset which is 67% of all my data. Then an evaluation dataset which is 33%.

They’ve been randomly shuffled. Somehow, there are some values in the evaluation dataset which didn’t appear in training. This is causing the following bug:

tensorflow.python.framework.errors_impl.InvalidArgumentError: indices[4] = 54 is not in [0, 53)

Which, after some googling, is because not all the vocabulary values were found in the training dataset. I want to just extend the vocab size but I’m unsure how to do it.

The relevant lines of code would be these ones I think:

for feature_name in CATEGORICAL_COLUMNS:
vocabulary = dftrain[feature_name].unique() # gets a list of all unique values from given feature column
feature_columns.append(tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary))

Which is a list, and not a scalar length. So I can’t simply add to it.

Any ideas or more information required?

submitted by /u/Cwlrs
[visit reddit] [comments]

Categories
Misc

How do I build tensorflow so it is optimised for build machine?

If I build tensorflow, will it be optimised for that host?

The command i am using is… bazel build —config=opt //tensor flow/tools/pip_package

Will it be optimised? Will it use the host’s full instruction set where it can? Will it avoid instructions the host does not support?

If this is the case. How is the formal release built? Does it override the default settings or is it built on a specified host?

I ask as the formal release uses instructions my host does not have. I am building and using in the same host. I’ve read up on why this has happened. Just not clear on trying to build for my host.

submitted by /u/BillyBag2
[visit reddit] [comments]

Categories
Misc

Saw this video under r/Python, and found it very helpful.

Saw this video under r/Python, and found it very helpful. submitted by /u/felix-thebest
[visit reddit] [comments]