# Why use separable convolutions on one channel input?

I'm currently working on the Text Classification Guide from Google. During step 4, they create a CNN with separable convolutions for use with word embeddings:

    def sepcnn_model(blocks,
filters,
kernel_size,
embedding_dim,
dropout_rate,
pool_size,
input_shape,
num_classes,
num_features,
use_pretrained_embedding=False,
is_embedding_trainable=False,
embedding_matrix=None):
"""Creates an instance of a separable CNN model.

# Arguments
blocks: int, number of pairs of sepCNN and pooling blocks in the model.
filters: int, output dimension of the layers.
kernel_size: int, length of the convolution window.
embedding_dim: int, dimension of the embedding vectors.
dropout_rate: float, percentage of input to drop at Dropout layers.
pool_size: int, factor by which to downscale input at MaxPooling layer.
input_shape: tuple, shape of input to the model.
num_classes: int, number of output classes.
num_features: int, number of words (embedding input dimension).
use_pretrained_embedding: bool, true if pre-trained embedding is on.
is_embedding_trainable: bool, true if embedding layer is trainable.
embedding_matrix: dict, dictionary with embedding coefficients.

# Returns
A sepCNN model instance.
"""
op_units, op_activation = _get_last_layer_units_and_activation(num_classes)
model = models.Sequential()

# Add embedding layer. If pre-trained embedding is used add weights to the
# embeddings layer and set trainable to input is_embedding_trainable flag.
if use_pretrained_embedding:
output_dim=embedding_dim,
input_length=input_shape[0],
weights=[embedding_matrix],
trainable=is_embedding_trainable))
else:
output_dim=embedding_dim,
input_length=input_shape[0]))

for _ in range(blocks-1):
kernel_size=kernel_size,
activation='relu',
bias_initializer='random_uniform',
depthwise_initializer='random_uniform',
kernel_size=kernel_size,
activation='relu',
bias_initializer='random_uniform',
depthwise_initializer='random_uniform',

kernel_size=kernel_size,
activation='relu',
bias_initializer='random_uniform',
depthwise_initializer='random_uniform',
kernel_size=kernel_size,
activation='relu',
bias_initializer='random_uniform',
depthwise_initializer='random_uniform',
return model


However, looking at the GitHub repo, they only use one channel word embeddings as input:

    def _get_embedding_matrix(word_index, embedding_data_dir, embedding_dim):
"""Gets embedding matrix from the embedding index data.
# Arguments
word_index: dict, word to index map that was generated from the data.
embedding_data_dir: string, path to the pre-training embeddings.
embedding_dim: int, dimension of the embedding vectors.
# Returns
dict, word vectors for words in word_index from pre-trained embedding.
# References:
https://nlp.stanford.edu/projects/glove/
http://nlp.stanford.edu/data/glove.6B.zip
"""

# Read the pre-trained embedding file and get word to word vector mappings.
embedding_matrix_all = {}

# We are using 200d GloVe embeddings.
fname = os.path.join(embedding_data_dir, 'glove.6B.200d.txt')
with open(fname) as f:
for line in f:  # Every line contains word followed by the vector value
values = line.split()
word = values[0]
coefs = np.asarray(values[1:], dtype='float32')
embedding_matrix_all[word] = coefs

# Prepare embedding matrix with just the words in our word_index dictionary
num_words = min(len(word_index) + 1, TOP_K)
embedding_matrix = np.zeros((num_words, embedding_dim))

for word, i in word_index.items():
if i >= TOP_K:
continue
embedding_vector = embedding_matrix_all.get(word)
if embedding_vector is not None:

My question is: Why do they use a SeparableConv1D layer as their first Convolution if the embedding layer only has one channel. From my understanding, separable convolutions only give computational benefits compared to normal convolutions when applied to multiple channels?
As far as I know, SeparableConv layer is theoretically identical to Conv if the input channel is 1. So, you are right. I think the reason why it is done in this way is only for program convenience. Notice there is a for _ in range(blocks-1): loop warpping those SeparableConv1D & MaxPooling1D blocks. The speed advantage of using SeparableConv starts from the second iteration.