Keras: Audio Classification on different dataset

Created on 30 Nov 2018  路  17Comments  路  Source: rstudio/keras

Hi, I just want to try an audio classification task on different dataset but get an error while training.
Could not figure out what should be changed. Could you help with that?

Epoch 1/10
Error in py_call_impl(callable, dots$args, dots$keywords) : 
  DataLossError: Attempted to pad to a smaller size than the input element.
     [[node IteratorGetNext_22 (defined at /Library/Frameworks/R.framework/Versions/3.5/Resources/library/keras/python/kerastools/generator.py:7)  = IteratorGetNext[output_shapes=[[?,98,257,?], [?,?]], output_types=[DT_FLOAT, DT_FLOAT], _device="/job:localhost/replica:0/task:0/device:CPU:0"](OneShotIterator_22)]]

Caused by op u'IteratorGetNext_22', defined at:
  File "/Library/Frameworks/R.framework/Versions/3.5/Resources/library/keras/python/kerastools/generator.py", line 7, in dataset_generator
    batch = iter.get_next()
  File "/Users/turgutabdullayev/.virtualenvs/r-tensorflow/lib/python2.7/site-packages/tensorflow/python/data/ops/iterator_ops.py", line 421, in get_next
    name=name)), self._output_types,
  File "/Users/turgutabdullayev/.virtualenvs/r-tensorflow/lib/python2.7/site-packages/tensorflow/python/ops/gen_dataset_ops.py", line 2069, in iterator_get_next
    output_shapes=output_shapes, name
In addition: Warning messages:
1: In normalizePath(path) : path[1]="": No such file or directory
2: In normalizePath(path) : path[1]="": No such file or directory

All 17 comments

Hi, please provide the exact code and dataset you're using (if possible, a small sample from the dataset that would produce the error).

Hi, please provide the exact code and dataset you're using (if possible, a small sample from the dataset that would produce the error).

The audio file is on my GitHub page,
And code is here

To make sure I'm running the same files as you, could you indicate which should be the actual paths used?

The script says

df <- data_frame(
  fname = files, 
  class = fname %>% str_extract("cats_dogs/train/.*/") %>% 
    str_replace_all("cats_dogs/train", "") %>%
    str_replace_all("/", ""),
  class_id = class %>% as.factor() %>% as.integer() - 1L
)

but the directories I get from the download are cats and dogs, with raw .wav files inside.

You are absolutely right. Sorry for that, I just shared a test (cause it is small) folder on GitHub and forgot to change path within script... Could you create a new folder and place them there, like:

files <- fs::dir_ls(
  path = "/Users/turgutabdullayev/Downloads/**new_folder**", 
  recursive = TRUE, 
  glob = "*.wav"
)


df <- data_frame(
  fname = files, 
  class = fname %>% str_extract("**new_folder**/.*/") %>% 
    str_replace_all(**"new_folder"**, "") %>%
    str_replace_all("/", ""),
  class_id = class %>% as.factor() %>% as.integer() - 1L
)

thanks, I see!

Well, from "printf-debugging"

print(spectrogram)

I see it fails on the 3rd file (for me), and somehow it's the value of n_chunks in

dataset_padded_batch(batch_size, list(shape(n_chunks, fft_size, NULL), shape(NULL)))

that doesn't work for this file.
If you change n_chunks to NULL, you get rid of this but the model isn't happy any more:

 ValueError: Error when checking input: expected conv2d_41_input to have shape (98, 257, 1) but got array with shape (377, 257, 1)

I think you should dig deeper into that whole __spectrogram__ thing and see what's going on (keep us posted too :-))

I think you should dig deeper into that whole spectrogram thing and see what's going on (keep us posted too :-))

After some days I could figure out many things =)

n_chunks              # We should not touch this

Instead, we should change the window_stride_ms = 10 to window_stride_ms = 20 _(I tested it on different dataset from here)._ So, for cats and dogs it should be the same strategy.

library(tfdatasets)

audio_ops <- tf$contrib$framework$python$ops$audio_ops

data_generator <- function(df, batch_size, shuffle = TRUE, 
                           window_size_ms = 28, window_stride_ms = 20)

That's it =)

This is for those who want to test audio class-n on different dataset:

_Change that value to different numbers_ in order to get the same shape here:

model %>%  
  layer_conv_2d(input_shape = c(49, 257, 1), 
                filters = 32, kernel_size = c(3,3), activation = 'relu') %>% 

# Otherwise you will get an error

ValueError: Error when checking input: expected conv2d_41_input to have shape (98, 257, 1) but got array with shape (377, 257, 1)

I got this shape by the following:

window_size_ms <- 28
window_stride_ms <- 20
window_size <- as.integer(16000*window_size_ms/1000)
stride <- as.integer(16000*window_stride_ms/1000)
fft_size <- as.integer(2^trunc(log(window_size, 2)) + 1)
n_chunks <- length(seq(window_size/2, 16000 - window_size/2, stride))

If you change n_chunks to NULL

and you can test batch structure like this:

sess <- tf$Session()
batch <- next_batch(ds_train) #error
str(sess$run(batch))

BTW, everytime you should get the same shape.

Great you were able to sort it out and make it work!

[I'd also like to look a bit into this when I get to it - which probably won't happen immediately - so I'll let it open for now.]

I'd also like to look a bit into this

Please share your solution later because I am facing errors again.

Sure! It may take a bit before I get to it though.

I am guessing the problem is probably due to some audio files have different sizes, and consequently their spectrograms have different dimensions.

I think there are 2 main options:

  • Parametrizing the spectrogram creation on the audio lenght.
  • Reshaping the spectrogram before getting it into the model. (there are some tf ops to reshape images, and you can consider the spectrogram like an image.)

Hi, I just took code snippet from this blog and would like to know whether it is the right way to solve this issue.

data_generator <- function(df, batch_size, shuffle = TRUE, 
                           window_size_ms = 2, window_stride_ms = 30) {

  #window_size <- as.integer(16000*window_size_ms/1000)
  #stride <- as.integer(16000*window_stride_ms/1000)
  #fft_size <- as.integer(2^trunc(log(window_size, 2)) + 1)
  #n_chunks <- length(seq(window_size/2, 16000 - window_size/2, stride))

  ds <- tensor_slices_dataset(df)

  if (shuffle) 
    ds <- ds %>% dataset_shuffle(buffer_size = 10)  

  ds <- ds %>%
    dataset_map(function(obs) {

      # decoding wav files

      #audio_binary <- tf$read_file(tf$reshape(obs$fname, shape = list()))

      audio_binary = tf$read_file(obs$fname)

      wav <- audio_ops$decode_wav(audio_binary, desired_channels = 1)

      # create the spectrogram
      spectrogram <- audio_ops$audio_spectrogram(
        wav$audio, 
        window_size = window_size, 
        stride = stride,
        magnitude_squared = TRUE
      )

      #spectrogram <- tf$log(tf$abs(spectrogram) + 0.01)
      #spectrogram <- tf$transpose(spectrogram, perm = c(1L, 2L, 0L))

      #brightness <- tf$placeholder(tf$float32, shape=list())
      brightness<-100
      mul <- tf$multiply(spectrogram, brightness)
      # Normalize pixels
      min_const<-tf$constant(255)
      minimum <- tf$minimum(mul, min_const)
      # Expand dims so we get the proper shape
      expand_dims <- tf$expand_dims(minimum, -1L)

      # Resize the spectrogram to input size of the model
      resize <- tf$image$resize_bilinear(expand_dims, c(128L, 128L))

      # Remove the trailing dimension
      squeeze <- tf$squeeze(resize, 0L)

      # Tensorflow spectrogram has time along y axis and frequencies along x axis
      # so we fix that
      flip <- tf$image$flip_left_right(squeeze)
      transpose <- tf$image$transpose_image(flip)

      # Convert image to 3 channels, it's still a grayscale image however
      grayscale <- tf$image$grayscale_to_rgb(transpose)

      # Cast to uint8 and encode as png
      cast <- tf$cast(grayscale, tf$uint8)
      png <- tf$image$encode_png(cast)
      # transform the class_id into a one-hot encoded vector
      response <- tf$one_hot(obs$class_id, 2L)

      list(png, response)
    }) %>%
    dataset_repeat()

  ds <- ds %>% 
    dataset_padded_batch(batch_size, list(shape(), shape(NULL)))

  ds
}

After that, train dataset looks like this:

List of 2
 $ :List of 10
  ..$ :锟絇NG


  ..$ :锟絇NG


  ..$ :锟絇NG


  ..$ :锟絇NG


  ..$ :锟絇NG


  ..$ :锟絇NG


  ..$ :锟絇NG


  ..$ :锟絇NG


  ..$ :锟絇NG


  ..$ :锟絇NG


  ..- attr(*, "dim")= int 10
 $ : num [1:10, 1:2] 1 1 0 0 1 1 0 0 0 0 ...

You shouldn't return a PNG encoded vector to the model. I think you could return the result from
squeeze instead.

Yes, it works now :-) Thank you so much!

I'm closing this as it was solved (planning on a short background-explaining post some time later this year :-))

I'd also like to look a bit into this

Please share your solution later because I am facing errors again.

I am having the same issue, it seems that the error seems to happen in this bit:

ds %>%
dataset_padded_batch(
batch_size = batch_size,
padded_shapes = list(tf$stack(list(
n_periods, n_coefs,-1L
)),
tf$constant(-1L, shape = shape(1L))),
drop_remainder = TRUE
)

I read in this post it could be due to the shape of the padded shapes

@mrry

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Mrugankakarte picture Mrugankakarte  路  5Comments

aliarsalankazmi picture aliarsalankazmi  路  4Comments

pbhogale picture pbhogale  路  5Comments

qade544 picture qade544  路  5Comments

LarsHill picture LarsHill  路  6Comments