Компилятор C может перестроить переменные стека?

Я думаю, что этот может служить вам. Я использовал только функции, которые включают в себя тензорный поток таким образом, что именно он управляет обратным распространением.

Если вы используете функции Python, вам придется программировать как вперед, так и назад. Но проблема в том, что вам нужно сохранить маски функции кусочной функции в «кэше» (лично я не знаю, как это делается, и было бы интересно узнать).

import numpy as np
import tensorflow as tf

def new_relu(x, k=0.2):
    part_1 = tf.to_float(tf.math.less_equal(0.0, x))
    part_2 = tf.to_float(tf.math.logical_and(tf.math.less_equal(-1.0, x), tf.math.less(x, 0.0)))
    part_3 = tf.to_float(tf.math.less(x, -1.0))
    return part_1*x + part_2*x*k #+ part_3*0

def new_relu_test():

    # create data
    x = tf.random_normal([10])*10000
    y = new_relu(x)
    with tf.Session():
        diff = tf.test.compute_gradient_error(x, [10], y, [10])
        print(diff)

    # use in dense
    x = tf.placeholder(shape=[None, 3], dtype=tf.float32)
    nn = tf.layers.dense(x, 3, activation=new_relu)

РЕДАКТИРОВАТЬ: Если вы хотите, чтобы второй параметр тоже был тензором, вы должны быть того же размера, что и входные данные.

import numpy as np
import tensorflow as tf

def new_relu(x, k=0.2):
    part_1 = tf.to_float(tf.math.less_equal(0.0, x))
    part_2 = tf.to_float(tf.math.logical_and(tf.math.less_equal(-1.0, x), tf.math.less(x, 0.0)))
    part_3 = tf.to_float(tf.math.less(x, -1.0))
    return part_1*x + part_2*x*k #+ part_3*0

def new_relu_test():
    # create data
    x = tf.random_normal([10])*10000
    y = new_relu(x)
    with tf.Session():
        diff = tf.test.compute_gradient_error(x, [10], y, [10])
        print(diff)

    # use in dense
    x = tf.placeholder(shape=[None, 3], dtype=tf.float32)
    x_b = tf.placeholder(shape=[None], dtype=tf.float32)
    nn_1 = tf.layers.dense(x, 3)
    nn_2 = tf.layers.dense(x, 3)
    nn = tf.layers.dense(nn_2, 1, activation=None)
    new_r = new_relu(x, tf.tile(tf.expand_dims(x_b, -1), [1, 3]))

    with tf.Session() as sess:
        sess.run(tf.initializers.global_variables())
        sess.run(new_r, feed_dict={x: np.random.rand(100, 3), x_b: np.random.rand(100)})

new_relu_test()

РЕДАКТИРОВАТЬ 2:

Использование conv2d

import numpy as np
import tensorflow as tf

def new_relu(x, k=0.2):
    part_1 = tf.to_float(tf.math.less_equal(0.0, x))
    part_2 = tf.to_float(tf.math.logical_and(tf.math.less_equal(-1.0, x), tf.math.less(x, 0.0)))
    part_3 = tf.to_float(tf.math.less(x, -1.0))
    return part_1*x + part_2*x*k #+ part_3*0

def new_relu_test():
    # create data
    x = tf.random_normal([10])*10000
    y = new_relu(x)
    with tf.Session():
        diff = tf.test.compute_gradient_error(x, [10], y, [10])
        print(diff)

    # use in dense
    x = tf.placeholder(shape=[None, 28, 28, 3], dtype=tf.float32)

    conv1_weights = tf.get_variable("weight",[3,3,3,32],initializer=tf.truncated_normal_initializer(stddev=0.1))
    conv1_biases = tf.get_variable("bias", [32], initializer=tf.constant_initializer(0.0))
    conv1 = tf.nn.conv2d(x, conv1_weights, strides=[1, 1, 1, 1], padding='SAME')
    relu1 = new_relu(tf.nn.bias_add(conv1, conv1_biases))

    with tf.Session() as sess:
        sess.run(tf.initializers.global_variables())
        sess.run(relu1, feed_dict={x: np.random.rand(100, 28, 28, 3)})
new_relu_test()
15
задан Destructor 21 May 2016 в 19:21
поделиться

11 ответов

Как нет ничего в стандарте, запрещающем это для C или компиляторов C++, да, компилятор может сделать это.

Это отличается для агрегатов (т.е. структуры), где относительный порядок должен быть поддержан, но тем не менее компилятор может вставить байты клавиатуры для достижения предпочтительного выравнивания.

IIRC более новые компиляторы MSVC используют ту свободу в своей борьбе с переполнением буфера местных жителей.

Как примечание стороны, в C++, порядок разрушения должен быть обратным порядком объявления, даже если компилятор переупорядочивает расположение памяти.

(Я не могу заключить в кавычки главу и стих, тем не менее, это из памяти.)

22
ответ дан 30 November 2019 в 23:48
поделиться

Компилятор даже не мог бы использовать стек вообще для данных. Если Вы находитесь на платформе, столь крошечной, что Вы волнуете приблизительно 8 по сравнению с 12 байтами стека, то вероятно, что будут компиляторы, которые довольно специализировали подходы. (Некоторая PIC и 8 051 компилятор приходят на ум),

Для какого процессора Вы компилируете?

4
ответ дан 30 November 2019 в 23:48
поделиться

Компилятор является даже бесплатным удалить переменную из стека и заставить его зарегистрироваться, только если анализ показывает, что адрес переменной никогда не берется/используется.

10
ответ дан 30 November 2019 в 23:48
поделиться

Компилятор для Texas Instruments 62xx серия DSP способна к и делает "целую оптимизацию программы". (можно выключить его),

Это - то, где Ваш код перестроен, не только местные жители. Таким образом, порядок выполнения заканчивает тем, что был не совсем, что Вы могли бы ожидать.

C и C++ на самом деле не обещают, модель памяти (в смысле говорят, что JVM), таким образом, вещи могут очень отличаться и все еще могут быть законными.

Для тех, кто не знает их, 62xx, семейство является 8 инструкциями на DSP такта; на уровне 750 МГц они действительно достигают максимума в 6e+9 инструкции. Часть времени так или иначе. Они действительно находят что-либо подобное выполнению, но упорядочивание инструкции сделано в компиляторе, не ЦП, как Intel x86.

PIC и встроенные платы Кролика не имеет стеков, если Вы не спрашиваете особенно приятно.

4
ответ дан 30 November 2019 в 23:48
поделиться

Мало того, что компилятор может переупорядочить расположение стека локальных переменных, это может присвоить их регистрам, присвоиться им для проживания иногда в регистрах и иногда на стеке, это может присвоить двух местных жителей тому же слоту в памяти (если их живые диапазоны не накладываются), и это может даже полностью устранить переменные.

39
ответ дан 30 November 2019 в 23:48
поделиться

Потребность стека даже не существует (на самом деле, стандарт C99 не имеет единственного происшествия слова "стеком"). Таким образом да, компилятор является бесплатным сделать независимо от того, что он хочет, пока это сохраняет семантику переменных с продолжительностью автоматического хранения.

Что касается примера: Я много раз встречался с ситуацией, где я не мог отобразить локальную переменную в отладчике, потому что он был сохранен в регистре.

10
ответ дан 30 November 2019 в 23:48
поделиться

Нет никакой потребности в досужих домыслах о том, чего стандарт C требует или не требует: недавние проекты в свободном доступе онлайн от рабочей группы ANSI/ISO.

0
ответ дан 30 November 2019 в 23:48
поделиться

AFAIK там - ничто в определении C или C++, указывающего, как компилятор должен заказать локальные переменные на стеке. Я сказал бы, что доверие, что компилятор может сделать в этом случае, является плохой идеей, потому что следующая версия Вашего компилятора может сделать это по-другому. Если Вы проводите время и усилие приказать, чтобы Ваши локальные переменные сохранили несколько байтов стека, те немного байтов должны быть действительно очень важными для функционирования Вашей системы.

0
ответ дан 30 November 2019 в 23:48
поделиться

Достойный компилятор поместит локальные переменные в регистры, если он может. Переменные должны только быть помещены в стек, если существует повышенное давление регистра (недостаточно комнаты) или если адрес переменной взят, означая, что это должно жить в памяти.

Насколько я знаю, нет ничего, что говорит, что переменные должны быть помещены в любое определенное местоположение или выравнивание на стеке для C/C++; компилятор поместит их везде, где является лучшим для производительности и/или независимо от того, что удобно для разработчиков компилятора.

0
ответ дан 30 November 2019 в 23:48
поделиться

это - специфические особенности компилятора, можно сделать его собственный компилятор, который сделал бы инверсию, если бы он хотел это тот путь.

0
ответ дан 30 November 2019 в 23:48
поделиться

Это не отвечает на Ваш вопрос, но здесь - мои 2 цента о связанной проблеме...

У меня не было проблемы оптимизации стекового пространства, но у меня была проблема неточного совмещения двойных переменных на стеке. Функция может быть вызвана от любой другой функции, и значение указателя вершины стека может иметь любое невыровненное значение. Таким образом, я придумал идею ниже. Это не исходный код, я просто записал это...

#pragma pack(push, 16)

typedef struct _S_speedy_struct{

 double fval[4];
 int64  lval[4];
 int32  ival[8];

}S_speedy_struct;

#pragma pack(pop)

int function(...)
{
  int i, t, rv;
  S_speedy_struct *ptr;
  char buff[112]; // sizeof(struct) + alignment

  // ugly , I know , but it works...
  t = (int)buff;
  t +=  15; // alignment - 1
  t &= -16; // alignment
  ptr = (S_speedy_struct *)t;

  // speedy code goes on...
}
0
ответ дан 30 November 2019 в 23:48
поделиться