1. Куча / Говнокод #11745

    +124

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    data = load('ex1data1.txt');
    X = data(:, 1); y = data(:, 2);
    m = length(y); % number of training examples
    X = [ones(m, 1), data(:,1)]; % Add a column of ones to x
    theta = zeros(2, 1); % initialize fitting parameters
    
    % Some gradient descent settings
    iterations = 1500;
    alpha = 0.01;
    
    function J = computeCost(X, y, theta)
      m = length(y); % number of training examples
      hypothesis = theta' * X';
      J = 1 / (2 * m) * sum((hypothesis' - y) .^ 2);
    endfunction
    
    % compute and display initial cost
    computeCost(X, y, theta)

    Язык: Матлаб / Октава.
    Что происходит: из массива создается матрица путем добавления еще одного такого же массива полностью заполненного единицами, а потом эта матрица умножается на вектор из двух элементов (первая колонка, соответственно, умножается на первый элемент вектора, вторая - на второй). Т.е. это равносильно вызову функции вида y(x) = Kx + b для всех членов исходного массива X. По сути происходит следующее: y(x_0, x_1) = K * x_1 + b * x_0, где x_0 всегда равен единице.
    Источник разглашать не буду.

    Запостил: wvxvw, 11 Сентября 2012

    Комментарии (31) RSS

    • >Источник разглашать не буду.
      Лаба.
      Ответить
      • А что, по вашему сайты на Матлабе пишут? Понятно, что лаба, но лаба лабе - рознь.
        Ответить
    • Зато параллелится код на ура (учитывая что матлаб и вычисление на GPU поддерживает).
      Ответить
      • Человек, который этот код написал, утверждал то же самое. Все равно мне как-то не по себе. Специально придумывать извращенный способ рассчета для того, чтобы это было проще распараллелить? А что если нормальный способ тоже хорошо распараллелится?
        Ответить
    • Ето копипаст ответа на задание с Курсеры. И притом ответ правильный. Хотя все операции транспонирования можно удалить, написав Х*theta. Но больше никаких признаков говнокода не замечено.
      Ответить
      • 1500 раз умножить на единицу - это, конечно, в порядке вещей. Да, материал именно от туда.
        Ответить
        • Операция производится над векторами. Ето намного быстрее чем через цикл. Я согласен, что в данном примере с обычной регрессией возможно время выполнения будет большим. Но при множественной регрессии (Х имеет несколько столбиков) будет наблюдаться обратное.
          Ответить
          • Если будет наблюдаться обратное - то это только говорит о том, что язык плохо пахнет, и поощряет идиотские решения в угоду более вменяемым. Нет никакой технической необходимости, чтобы перемножение матриц, какого бы размера они ни были было быстрее чем ровно такое же количество умножений и сложений сделанных в цикле.
            Ответить
    • Я прогнал по Матлабу. Если простая регрессия - сложение kX+b быстрее. Но если в X 3 столбца (помимо единичек) и 1млн строк, немного быстрее полностью векторизированный вариант (8.63 против 9.55 с. для 100 повторений).
      Ответить
      • ХЗ, у меня Матлаба вообще нет. Пользовался Октавой. Но я ее плохо знаю / у меня челюсти сводит от кода на этом замечательном языке. Ну а если у них получилось так, что перемножение матриц быстрее тех же действий сделанных в цикле - ну так, что можно об этом сказать - херовые у них циклы :/
        Ответить
        • Ну почему сразу плохие циклы. Просто хорошие у них вектора. Видимо SIMD инструкции юзают при умножении.

          А распараллелить обычный цикл - задача совсем не тривиальная.
          Ответить
          • Кстати я даже циклы не использовал: theta*X против theta(:,2:4)*X+theta(:,1)
            Ответить
          • Я реализациями такого уровня не занимался, поэтому сказать ничего не могу. Попадались академические бумаги, в которых такие оптимизации рассматривались (для циклов). В теории, я не вижу сложностей в реализации распараллеливания для данной ситуации, когда заранее известно размер массива, и так же известно что никакого ветвления до определенного момента не будет, и поэтому можно скопировать сразу несколько значений из массива и применить к ним параллельно одну и ту же операцию.
            С другой стороны - такой выигрыш станет неактуальным, когда количество колонок будет выше чем количество ячеек куда можно одновременно поместить информацию (хз сколько их может быть, но наверняка это двузначные цифры).
            Ответить
            • Согласитесь, что распараллеливание цикла не так тривиально, как распараллеливание векторизованных операций. В одном случае нужно изучать все тело цикла, и принимать какие-то решения, во втором - банальнейший код для распихивания значений по SIMD регистрам, локализованный внутри кода операторов.
              Ответить
              • Ну не невыполнимая же. Если бы там каие-то чудеса надо было делать - одно дело\
                , но вроде ж нет.
                Или, хз, меня просто сам язык выводит из себя таким подходом. Напоминает школь\
                ный Фортран, где было 100500 разных встроенных функций для вывода на матричные\
                принтеры с разным размером матрицы, а строки склеивались через задний проход.\
                Так и тут, универсальное, при чем хорошее решение работает хуже чем какая-то \
                встроенная функция, которую нужно заучивать...
                Ответить
              • Упс, выше комментарий - мой, чет он только как-то интересно скопировался :)
                Ответить
        • Matlab=Octave в красивой обертке, + блекджек и шлюхи
          Ответить
          • + овер 9000 бабла
            Ответить
          • Точнее наоборот - Octave это матлаб без оберток, без тулбоксов, без шлюх с бледжеком, но бесплатный. Ну и не знаю как у него с расчетами на GPU, с компиляцией в С или с поддержкой внешних устройств, но подозреваю что плохо.
            Ответить
        • циклы не нужны
          Ответить
    • Ок, признаю, что перевес не настолько очевидный. Я прокрутил theta*X против цикла вложенного в цикл. При 3 столбцах 8.62 против 3.61 - в пользу цикла. При 100 столбцах (100тысяч строк) 18.34 против 20.98 - в пользу векторов. Но все-таки математически theta*X красивее чем for j=1:100000 for k=1:100 x(j)=x(j)+a(j,k)*theta(k); end;end;
      Ответить
      • Да чем красивее - тем что делается бесполезная операция кучу раз? Или тем, что поля в векторе - они просто поля в векторе, и угадать, какое из них константа, а какое - множитель в таком раскладе можно только методом тыка?
        Типичный пример уродского кода написанного сотрудником кафедры информатики/чего-то там. Боже упаси от такого в обычной жизни: я бы только за названия переменных пальцы в двери.
        Ответить
        • Красивее тем что векторизовано. Ну и краткость записи важна. А экономить на умножениях на 1 - нафиг надо.
          Ответить
          • Пипец... краткость записи важна... ну так напишите функцию и потом вызывайте сколько влезет, по-любому короче будет. По той же причине ученый муж, который эту херню написал, наверное и аргументы назвал X и y, вместо features и prices.
            Ответить
            • Конечно, ведь hypothesis = theta * X; и читается легче, и считается быстрее чем hypothesis = theta(2)*features+theta(1);
              Да и вообще - если это функция регрессии, то зачем в ней упоминать какие-то prices и features?
              Ответить
              • Только что ж выяснили, что не быстрее.
                И, да, такие вещи тяжело понять без сравнения. В лучших практиках любого популярного языка всегда вам скажут, что называть переменные одной буквой - плохо, и нужно давать осмысленные имена.

                Чтобы вы не сомневались:
                theta = '\xCE'

                это осмысленное название, соответствующее значению, понятное любому человеку, который будет этот код читать. А то, что вам кажется понятным, на самом деле никому не понятно, более того, на заучивание этой бессистемной херни уходит драгоценное время и человеческая память.
                features - не какие-то, так именно принято называть данные по которым расчитывается значение. Это вполне себе распространенное в этой области понятие которое однозначно описывает именно то, что передается в переменной Х. Но, в отличие от "Х", для англоязычного читателя, это еще и объясняет то, что стоит за этой переменной.
                Ответить
        • hello world!!!
          Ответить

    Добавить комментарий