Stanford ML and AI Classes

А я ведь тоже их осилил, и даже получил 98.1% за AI, завидуйте! Коллеги-блоггеры, к счастью, все уже написали за меня, так что кто интересуется темой, наверняка уже в курсе. Я добавлю только немного личных ощущений.

ML Class близок к идеалу. Именно таким должен быть настоящий учебный курс — невероятно простым, невыносимо нудным, но при этом дающим твердое понимание того, что происходит и как это работает. Рижским бальзамом на душу льются слова Andrew Ng: «Если вы это не понимаете, не переживайте, сейчас я расскажу, поймете» или «Если вы это не понимаете, не переживайте, я тоже не понимаю, это вам не нужно«. Ну и прочие подобные высказывания и шутки вроде «Если вы эксперт в линейной алгебре и знаете, что такое собственные вектора, то …» доставляют. Столько студентов сразу почувствовали себя экспертами в линейной алгебре! Отдельная благодарность за возможность ускорить лекции в 1.2 и 1.5 раза.

AI Class имеет гораздо больший охват материала, но при этом он менее проработанный. Куча несогласованной терминологии, много недосказанного, вопросы иногда расплывчаты и имеют слабое отношение к тексту. Постоянно происходят какие-то технические накладки, то сроки отодвигаются, то публикуются уточнения к вопросам, то еще какая напасть. Это не говоря уже об очаровательном немецком акценте Prof. Sebastian Thrun, которого я, в отличие от ускоренного Andrew Ng, понимал только процентов на 95 — некоторые фразы не могли понять даже native speakers. Но, несмотря на все недостатки, получился очень неплохой обзорный курс.

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

В целом нисколько не жалею, но курсы будущего семестра — разве что в пассивном режиме посмотрю.

John McCarthy

Thanks for LISP and AI.
RIP.

Черт, да что же это за месяц такой…

Dennis Ritchie

Thanks for C and UNIX.
RIP.

Альтернативное мнение об аспирантском курсе философии науки

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


Категорически не соглашусь. Лично для меня курс философии науки стал, не побоюсь этого слова, откровением. Можно сказать, поворотным пунктом. Когда в школе и в вузе проходят различные науки, совершенно не затрагивают тему того, насколько мы можем быть уверены в предлагаемом знании. И у каждого слушателя формируется своё весьма наивное представление о сущности истины и человеческого знания. Кто-то, например, освоил какой-то метод в какой-то области, сидит и только его применяет, а всё остальное считает ересью. А кто-то, скажем, любое порождение своего мозга принимает за великое открытие. Кто-то считает математику непогрешимой, а кто-то – что математика вообще ни на что не способна. Немалая доля людей вовсе науку не признаёт, а верит в различное НЛО и т. п.

Курс же философии науки знакомит нас с тем, как различные (не самые глупые) люди подходили к решению означенной проблемы. А проблема очень серьёзная – можем ли мы доверять научному или какому-либо ещё знанию? Как нынче принято говорить, краткий ответ – нет. Но если мы углубимся ещё немного, то оказывается, что лучше всё же доверять научному знанию, чем не доверять. В общем, там очень много весёлого, так в двух словах не перескажешь. Скажу лишь, что современной науке по моему представлению наиболее соответствует эволюционная эпистемология, а современному общественному сознанию – постмодернизм. Разумеется, сей курс не даёт правильного ответа – именно в силу невозможности абсолютного познания истины. Но он заставляет задуматься над тем, правильно ли то, что ты делаешь. Я категорически утверждаю, что философия науки необходима любому человеку, претендующему на то, что он занимается наукой, а не просто наливает раствор А в раствор Б.

Возможно, автору просто не повезло с преподавателями оного курса.


Я вам тоже могу открыто признаться, что не мог терпеть философию до тех пор, пока не прослушал курс философии науки в аспирантуре. В том числе когда проходил «философию» на четвёртом курсе.

Я совершенно с вами согласен в том, что философия как таковая не может быть единственной профессией – это всё равно, что заниматься архитектурой, не зная, как кладут кирпичи и куда попадают отходы из унитаза. Можно заметить, что ни один признанный философ не занимался исключительно рассуждениями о вещах в себе.

> В этой области множество людей столетиями придумывали термины, «законы» и «принципы».

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

> до какого-нибудь Витгенштейна

Витгенштейн, равно как и вся философия науки двадцатого века, совершенно напрямую связан с математикой и проблемами построения искусственного интеллекта. Ещё раз повторю, что ни его, ни любого другого философа не следует принимать на веру. Просто полезно на минуту представить себя в его шкуре.

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

А вот для чего, скажем, программисты алгоритмы проходят? Достаточно было бы обучить кодить и компилять, а коли человек достаточно умный, то до всех необходимых алгоритмов сам додумается. Конечно, это грубая аналогия, но смысл именно такой. Мировоззрение, конечно, за самого человека никто не сформирует. Но если он будет выбирать подходящее мировоззрение не только из собственных домыслов, но и на основании предыдущего опыта человечества – то он сможет сделать это более адекватно. Конечно, научное мировоззрение неявно сквозит в большинстве специальных курсов. Но, как известно, явное лучше неявного.

> Нет, я согласен, что при наличии хорошего преподавателя это может быть даже интересно, но нужно ли?

А зачем вообще общеобразовательные предметы проходят? Для того, чтобы человек видел перспективу, а не становился специалистом по правой ноздре. Другое дело, что т. н. гуманитарные предметы действительно в массе своей преподаются совершенно паскудным образом. Видимо, потому, что в гуманитарии идут в основном люди, у которых не сложились отношения с математикой и которые посвящают всю оставшуются жизнь убеждению окружающих, что плохи не они, а математика.

Ежели спрашивать лично меня – то я бы исключил литературу и русский язык из школьной программы за полной бесполезностью. Оставил бы только чтение-запись в начальной школе.


Кстати, вот ещё вспомнил. Одна из основных задач философии науки – это отличать науку от ненауки. В связи с нынешним засильем мракобесия и «альтернативной» науки это становится как никогда актуально. Грубо говоря, учёный, занимавшийся только наукой и не занимавшийся философией, скорее всего, правильно определит, кто есть кто, по крайней мере в своей области. Но вот убедить другого человека, что это так – это уже задача посложнее. Скорее всего, его аргументы сведутся к «это же очевидно любому здравомыслящему человеку» и «пойди ещё раз поучись в школе». Тогда как знакомство с философией и методологией науки даёт некоторые критерии (прежде всего фальсифицируемость) и приёмы убеждения. Хотя, к сожалению, переубедить «адепта» всё равно почти никогда не получается, но по крайней мере ты сам от такого спора не будешь погружаться в состояние отчаяния от осознания своего бессилия оправдать научную точку зрения.


Из конкретных философских трактатов могу порекомендовать разве что статью Карла Поппера об эволюционной эпистемологии http://www.keldysh.ru/pages/mrbur-web/philosophy/popper.html . Также не совсем по теме, но всё же – Ричард Докинз «Эгоистичный ген».

Случайно придумал quine на C

Для тех, кто не знает: quine (квайн) — это программа, которая при запуске выводит свой исходный текст.

Что интересно, мой вариант более чем вдвое короче, чем представленный в Википедии.

main(){char*p="main(){char*p=%c%s%c,c='%c',s[256];sprintf(s,p,c,p,c,c);puts(s);}",c='"',s[256];sprintf(s,p,c,p,c,c);puts(s);}

Изобрел я его совершенно случайно как побочный эффект своих рабочих дел. Опечатавшись, указал в printf() форматную строку как один из подставляемых аргументов, подставив тем самым форматную строку саму в себя. Сразу появились ассоциации с квайнами, повозился минут 15 — и готово. Заодно запостил в соответствующий раздел Codegolf@Stackexchange.

Добавлено

Оказывается, этот подход уже сто лет назад как придумали, и программа намного короче:

char*f="char*f=%c%s%c;main(){printf(f,34,f,34,10);}%c";main(){printf(f,34,f,34,10);}

В общем, я изобрел велосипед, ура.

УжасноПлохоНормальноХорошоОтлично (1 голосов, средний: 3,00 из 5)
Loading ... Loading ...

Как отбросить непрочитанные символы из cin?

Зачем отбрасывать символы? Попробуем решить такую задачу: нужно прочитать из cin целое число, причем если вместо целого числа нам подсунут какую-нибудь гадость, нужно сообщить об этом и попытаться прочитать число снова. Попытка номер один:

1
2
3
4
5
6
7
using namespace std;
int value = 0;
while (not (cin >> value)) {
    cout << "Invalid format" << endl;
    cin.clear();
}
cout << "Your input: " << value << endl;

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

Беглый гуглеж приводит меня к функции istream::sync(), которая, как говорит один источник, делает именно то, что нам нужно:

Synchronizes the buffer associated with the stream to its controlled input sequence. This effectively means that the unread characters in the buffer are discarded.

Что ж, попробуем:

1
2
3
4
5
6
7
8
using namespace std;
int value = 0;
while (not (cin >> value)) {
    cout << "Invalid format" << endl;
    cin.clear();
    cin.sync();
}
cout << "Your input: " << value << endl;

Хм. В моей системе результат не изменился, код работает точно так же, как и первый. Беда в том, что функция istream::sync() в некоторых реализациях стандартной библиотеки таки отбрасывает непрочитанные символы. Но не в моем случае.

А я человек простой — лезу в код своей стандартной библиотеки и смотрю что да как. Выходит, что istream::sync() вызывает stdio_sync_filebuf::pubsync(), которая вызывает stdio_sync_filebuf::sync(), которая, наконец, вызывает fflush(stdin). Понятно, что fflush(stdin) не может оказать никакого влияния на входной буфер cin.

Так что упомянутый выше «один источник» не стоит считать истиной в последней инстанции. Но надо сказать, что попытки найти истину в стандарте — еще более неблагодарное занятие.

В общем, правильное решение заключается в использовании функции istream::ignore() таким вот образом:

1
2
3
4
5
6
7
8
using namespace std;
int value = 0;
while (not (cin >> value)) {
    cout << "Invalid format" << endl;
    cin.clear();
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
cout << "Your input: " << value << endl;

Надо отметить, что вызов ignore() неплохо бы вставлять даже после успешного ввода, так как при вводе строки «123qwe» первые три символа будут прочитаны и распознаны как число, а «qwe» останутся во входном буфере и будут портить жизнь при следующем чтении. Еще одна тонкость — обработка конца файла. Если пользователь в ответ на приглашение к вводу нажмет Ctrl+D или что там в вашей системе для этого предназначено, то программа вместо того, чтобы завершиться, сообщит о неверном формате и предложит ввести число еще раз. Поэтому по-хорошему код должен быть вроде этого (вся программа):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <limits>
using namespace std;
template <typename Type>
bool read_value(const std::string &prompt, Type &value)
{
    bool repeat = true;
    bool eof = cin.eof();
    while (repeat and not eof) {
        cout << prompt << ": ";
        cin >> value;
        eof = cin.eof();
        repeat = cin.fail() and not eof;
        if (repeat) {
            cout << "***Invalid data format!" << endl;
            cin.clear();
        } else if (eof) {
            cout << "(EOF)" << endl;
        }
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
    return not eof;
}
int main()
{
    int value = 0;
    while (read_value("Input integer", value))
        cout << "Your input: " << value << endl;
}

Но и в этом, казалось бы, безошибочном, коде затаилась пара граблей. Например, что если функцию read_value() использовать для ввода символов или строк? Сумеем мы ввести символ пробела? Сумеем ли ввести строку из нескольких слов, разделенных пробелами? Хрен! С вводом символа пробела еще несложно — надо только использовать манипулятор noskipws, а вот ввод строк с пробелами потребует перегрузки read_value() и использования getline() вместо оператора >>.

В общем, писать на C++ — сплошное счастье.
УжасноПлохоНормальноХорошоОтлично (1 голосов, средний: 5,00 из 5)
Loading ... Loading ...