<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def describe_trainable_vars():
 """ Print a description of the current model parameters. Skip variables starting with "tower", as they are just duplicates built by data-parallel logic. """

    train_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES)
    if len(train_vars) == 0:
        logger.warn("No trainable variables in the graph!")
        return
    total = 0
    total_bytes = 0
    data = []
    for v in train_vars:
        if v.name.startswith('tower'):
            continue
        shape = v.get_shape()
        ele = shape.num_elements()
        if ele is None:
            logger.warn("Shape of variable {} is not fully defined but {}.".format(v.name, shape))
            ele = 0
        try:
            shape = shape.as_list()
        except ValueError:
            shape = '<unknown>'

        total += ele
        total_bytes += ele * v.dtype.size
        data.append([v.name, shape, ele, v.device, v.dtype.base_dtype.name])
    headers = ['name', 'shape', '#elements', 'device', 'dtype']

    dtypes = list(set([x[4] for x in data]))
    if len(dtypes) == 1 and dtypes[0] == "float32":
        # don't log the dtype if all vars are float32 (default dtype)
        for x in data:
            del x[4]
        del headers[4]

    devices = set([x[3] for x in data])
    if len(devices) == 1:
        # don't log the device if all vars on the same device
        for x in data:
            del x[3]
        del headers[3]

    table = tabulate(data, headers=headers)

    size_mb = total_bytes / 1024.0**2
    summary_msg = colored(
        "\nNumber of trainable variables: {}".format(len(data)) +
        "\nNumber of parameters (elements): {}".format(total) +
        "\nStorage space needed for all trainable variables: {:.02f}MB".format(size_mb),
        'cyan')
    logger.info(colored("List of Trainable Variables: \n", 'cyan') + table + summary_msg)