В школе во мне убили любовь к гуманитарным наукам, сейчас возрождаю это все. Не легко. В то время как по точным наукам я всегда делал на 80% быстрее все, что положено: контрольные всем 4-5 вариантам писал, конспект дома за полчасика готовил на пару уроков вперед, а на уроке троллил учительку указывая на ее ошибки, чтобы знала как это неприятно перед всем классом указывать на ошибки учеников, олимпиады и т.д. Для меня было нормально взять в библиотеке пособие для преподавателей и учить по нему, потому как там интеерснее было, чем в учебнике. Так что эта история тру.
Скажем так, то что написала Автор - это предпринимательство в образовании своих детей. И это в ногу со временем.
Не так давно друг спросил стоит ли ему записаться как я на уроки фртепиано. Я в это время как раз читал книгу Норбекова, на страницах которой автор меня изрядно попинал. Вот я и решил написать другу ответ. А поже выложить его в public, чтоб code reuse.
На вопрос друга "Саш, всё думаю, стоит ли звонить учителю форте. Что ты можешь позитивного сказать про неё?" Остапа понесло, ия написал следующее:
Давай рассскажу тебе негативного, чтобы был повод не пойти на первый урок. Учитель может тебе не подойти, вы оба взрослые люди, со своими жизненными позициями, может просто не получиться.
Но а таком случае, ты лишишься 150 грн и будешь иметь опыт. А один звонок со словами "это немного не то, что я хотел" расторгнет ваш устный договор.
Я шел на первй свой урок с этими мыслями.
Первый урок мне понравился очень, второй мне не понравился вообще (мало хвалили за то, что я успел сделать и уделяли внимание тому, что не успел), третий урок понравился еще больше чем первый. В общем я решил оставаться. А еще я заплатил за месяц вперед, так что теперь еще и RoI не дает сорваться с крючка.
Вывод со второго урока сделал - мне надо расчищать время каждый день под домашнее задание, тогда все будет ок. Если не делаю домашнее задание, то включается негатив и мысли, как бы не пойти на урок. А есл исделаю - хочется посморее показать его, домашку.
По теории учитель дает каждый раз то, что я сам не нагуглил. Кроме того постоянно следит за тем, как я держу руки, как извлекаю звук - этому с ютьюбом не научишься. Собственно за этим я и шел к учителю.
А еще, урок с самого утра как-то особенно меняет весь день. Один урок у нас был на 7:30. А в 9:30 я уже в офисе, довольный от того, что с самого утра успел сделать.
Я думаю стоит ходить учителю форте, если ты никогда не ходил к учителю форте и думаешь сходить ли, а может нет. Одно дело мыслями подпитывать неуверенность, а другое пойти и посомтреть как оно будет. Я боялся вообще подходить к инструменту, потом меня поставили перед фактом и дали синтезатор со словами - делай что хочешь. Любопыттство победило.
Потом я понял, что ничего в этом страшного нет - начал брынчать, но в какой-то момент понял, что подпер потолок и больше мне ютьюб не даст. Стал думать, пойти ли к учителю. Долго искал отмазки, почему я не иду к нему - небыло кого-то, кто бы подсказал хорошего учителя недалеко.
Но когда я встретил такого парня у нас в офисе, и даже договорился с ним сходить к его учителю, взял его номер телефона и удивился стоимости занятий в месяц - всего 500 грн, я все же не нашел времени пойти к нему на первый урок, зато нашел купу отмазок.
Потом мне намекнула потдруга, что одна наша коллега занимается с учителем, и я занес в туду, что надо бы разузнать что-где-когда и так удачно забыл это все в бездне свое GTD.
Потом мне коллега сама скинула в скайп, как она выступает на концерте, просто, по дружески. Я решил развить тему. Разговорились. Узнал про учителя ее. Коллега предложила мне сходить к ней на день рождения и договориться. Я согласился, но потом как-то стал искать отмазки и даже нашел в то утро пару достойных. Но потом все же собрался и пошел на встречу.
На дне рождения меня попросили сыграть что я умею, после всего того как ее ученики красиво играли, то как я играл звучало примитивно (на синтезаторе я еще как нибудь играл сносно, а на пианино я не привык - там физика другая, и звучало мялко говоря не очень). Меня привели в пример, как не стоит учиться по ютьюбу. Я надул бульку и решил, что не пойду на урок. По дороге домой понял, что снова нашел себе удобную отмазку и все же решил сходить на первый урок, который меня приятно удивил...
Я уверен, что меня время от времени будет посещать еще ряд отговорок, но надеюсь, как это войдет в привычку - заниматься музыкой каждый день, тогда они переведутся.
Вообще отмазки эти, как тараканы, от них сложно избавиться, но если не пытаться, то они будут жить рядом постоянно. Если, конечно, ты знаешь, что за напасть эти милые усатые насекомые.
А еще мне очень нравится музыка, которая звучит тут - я ее слушаю целыми днями.
Который раз ловлю себя на мысли, что на тренинге под названием JavaSE, который веду я учу не самой джаве, а чему-то другому. Тому, что считаю важным.
Для меня большей ценностью являются не знания конкретного языка, а абстрактные правила работы с ним - ооп, рефаткоринг. Подходы, с помощью которых разработка становится проще - TDD, парное программирование. Процесс, который позволит эффективнее выполнять цель "хэппи заказчик" - agile. Но так же уделяю внимание своему хэппинесс - timemanagement, как сделать из хобби работу, фан каждый день. Внимание и своему внутреннему я - медитации, возможности мозга, самоанализ.
Вот как можно иначе описать вот такой вот ответ, который сегодня в скайпе дал студенту задавшему простой вопрос "а что лучше так или эдак"? Где тут java?
....но в будущем делай выбор на основе внутреннего чувства беспокойства по поводу результата. То что меньше парит, то сегодня и выбирай - завтра все равно перепишешь свой код :)
Экспериментируй! У тебя всегда должно быть минимум 5 вариантов выбора. А выбор не вынужденным, а осознанным. После того как сделаешь выбор, должно стать легче. Значит выбор на сегодня правильный. Но у тебя не будет 5 вариантов выбора, пока ты не попробуешь их всех. А потому экспериментируй!
С другой стороны, когда экспериментируешь, наоборот должно становиться волнительно. Иначе не выйдешь за рамки.
И еще - это уже очень здорово, что тебя сегодня волнует структура твоего кода....
И таких замечаний полно. Вот это
Возвращайся к тому, что тут описано еще раз и еще раз, пока это не сделается твоей привычкой. Только раз прочитать - недостаточно. Пробуй все, что тут (и дальше по тренингу) описано, сделать своей привычкой. Но для начала не верь всему тому, что тут описано - перепроверяй на личном опыте! А как убедишься, что работает - сделай это своей привычкой, повторяя снова и снова. Между "знать" и "делать" огромная пропасть.
И это на тренинге по java :)
Лично я считаю что джаву можно только преподавать - то есть пересказывать все то, что сказано в учебнике. Учить же, для меня немного другое - помочь ученику помочь самому себе разобраться. Да-да, там два слова "помочь".
Был недавно разговор с другом что должен и что не должен делать перподаватель (говорили про вуз). Вот тут то я и разделил понятия учителя и преподавателя. Преподаватель должен позаботиться о том, что знания учащемуся были доставлены, а потом проверить как учащийся их освоил. Заинтересовать - не его задача. Учитель же помогает сделать так, чтобы знания приносили пользу. В его задачу входит так же ответственность за то, чтобы ученику было интересно, иначе ученика стоит отпустить (т.е. опять же помочь) изучать что-то другое.
Вообще каждый сам состоянии себе выбрать свой путь, так же правильно и то, что у каждого свой уникальный путь, даже если если место назначения одно. Учитель может только помочь. Идти должен каждый сам.
А граблей натыкано достаточно в программе. Если там есть глюк, то я не спешу его исправлять - оставлю как есть, а потом опишу почему было больно. Блин, ну так веселее. Тренинг ведь парктический! Должно быть больно. Должна быть креппатура и синяки. Иначе забуется.
Стараюсь отвечать так, чтобы чтобы после ответа было еще больше вопросов, чем до него. Делаю это частично от того, что все рассказать не успеть и есть много дел по-интереснее чем простое пересказывание чего-то кому-то. Так же некоим образом не хочу нести ответственность за то, что может быть услышано от меня. Слово "Выбор" - частый гость в моем языке. Делая выбор лично, ученик осознает свою ответственность.
Порой бывает, что ученик пытается сделать что-то типа этого "ты скажи, а я потом...". Но я то вижу, что это попытка переложить ответственность. Так и спрашиваю: "ты сейчас меня свою ответственность на меня пытаешься переложить?" А потом задаю вопрос, который заставляет задуматься, почему так случилось.
Вообще айтишники народ креативный, им нравится решать головоломки и делегировать рутинку. Если решение придумал кто-то другой - это скучно, это рутинка. Потому я прошу не верить мне на слово, а перепроверять все то о чем говорю. Но если уж поверил, то рекомендую сделать своей привычкой. А как привычка образовалась, то предлагаю отказаться от нее. Если ученик выбрал вариант А, то я показываю ему вариант Б и говорю о недостатках А, если наоборот выбор пал на Б, то хвалю вариант А.
Это все заставляет подумать. Не тупо выполнить указание, а подумать. Так же это заставляет думать и меня. Это здорово. Став тренером я по-настоящему стал учиться. Как минимум стал учиться задавать вопросы. А задав вопросы приходится самому искать ответы. А это уже самообразование.
На ровном месте можно задать вопрос, который заставит погрузиться в глубокие размышления. У каждого ученика в каждом отдельно взятом контексте - вопрос свой. И надо слушать. Много слушать. А потом бамц, и все - вопрос озвучен. Дальше говорить не имеет никакого смысла. Ученик сам ко всему прийдет. Ему надо время.
Часто нужно написать 100500 буков в скайпе или написать целый пост в блоге (вики), или пол часа что-то объяснять, пока в голове не случится инсайт - чик и есть ответ (или вопрос, смотря что искал). Одно предложение на русском, которое в себе скрывает все то, что ты говорил или делал до сих пор. Как бы заархивированное. Но разархивировать его можно по разному - и всегда что-то новое. Вот это интересно. Те кто занимается тренингами - знает об этой функции мозга.
Но тут стоит уделять время размышлению. Если просто пилить-пилить-пилить-плить, то нифига нового в голове не родится. Делать паузы и отдыхать. Переключаться с работы на хобби и обратно. Спать во время рабочего дня - это все позволяет переосмыслить. Иначе неэффективно. Иначе как робот. Тупо исполнитель.
Другой раз ляпну какую-то глупость, а потом думаю, как бы ее интегрировать вовсе то, что уже было сказано. Решение находится. Иногда специально так делаю, если скучно совсем. Ведь если появилось в голове - это значит, что оно что-то важное, особенно если мысль нова. Мозг это не генератор случайных чисел - мозг это генератор уникального для каждого автора ряда чисел, но в то же время не определяющего его однозначно. Этому и учу - проявлять свою уникальность. Генерить контент. Каким бы он ни был.
А вообще, общение - это шахматы. Общение это и дар и, одновременно, самый большой геморрой, которым наделила природа человека размуного. Играть в общение мне нравится. искать подход. Задавать вопросы. Слушать. Писать. Заражать идеей. Удивлять.
Этой попыткой я сильно приблизил судный день, ведь одной моей мечтой из детства было создать ИИ, позже оцифровать свой мозг. Шутка. Но немного покодим.
Долго этот таск висел в туду и все же я его решил реализовать. Спасибо Сереге и Костику, ведь именно им я рассказал за ужином, как оцифровали нейрон и что такое нейронная сетка. Знал я это по рассказам в википедии.
Итак я наткнулся на видео. Там все понятно описано.
Вся соль в синапсах и том, как мы меняем их "сопротивление". Это все математически должно быть доказано, что делай так и будет тебе счастье. Так что пока экспериментирую с тем что есть.
Идем по очереди. И начнем естественно с тестов.
package perceptron;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
public class AndNeuronTest extends AbstractNeuronTest {
@Override
Patterns getPattern() {
return new Patterns(new double[][]{
{0, 0, 0},
{0, 1, 0},
{1, 0, 0},
{1, 1, 1},
});
}
@Test
public void should0when0and0(){
assertEquals(0d, neuron.process(0, 0));
}
@Test
public void should0when0and1(){
assertEquals(0d, neuron.process(0, 1));
}
@Test
public void should0when1and0(){
assertEquals(0d, neuron.process(1, 0));
}
@Test
public void should1when1and1(){
assertEquals(1d, neuron.process(1, 1));
}
}
Тест на то, что обученный персептрон выполняет возложенные на него функции.
Родитель инкапсулирует обучение персептрона по шаблону.
package perceptron;
import org.junit.Before;
public abstract class AbstractNeuronTest {
protected Neuron neuron;
protected Teacher teacher;
@Before
public void teachPerceptron() {
teacher = new Teacher(getPattern());
neuron = teacher.teach();
}
abstract Patterns getPattern();
}
А делалось это для того, чтобы сделать еще пару тестов на OR и NOT операции
package perceptron;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
public class OrNeuronTest extends AbstractNeuronTest {
@Override
Patterns getPattern() {
return new Patterns(new double[][]{
{0, 0, 0},
{0, 1, 1},
{1, 0, 1},
{1, 1, 1},
});
}
@Test
public void should0when0or0(){
assertEquals(0d, neuron.process(0, 0));
}
@Test
public void should1when0or1(){
assertEquals(1d, neuron.process(0, 1));
}
@Test
public void should1when1or0(){
assertEquals(1d, neuron.process(1, 0));
}
@Test
public void should1when1or1(){
assertEquals(1d, neuron.process(1, 1));
}
}
И еще один
package perceptron;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
public class NotNeuronTest extends AbstractNeuronTest {
private static int STUB = 1;
@Override
Patterns getPattern() {
return new Patterns(new double[][]{
{STUB, 0, 1},
{STUB, 1, 0},
});
}
@Test
public void should0whenNot1(){
assertEquals(0d, neuron.process(STUB, 1));
}
@Test
public void should1whenNot0(){
assertEquals(1d, neuron.process(STUB, 0));
}
}
Нейрон - это на самом деле интерфейс
package perceptron;
public interface Neuron {
double process(double... input);
}
Но что дальше?
Разберем самый простой случай (почему самый? а так, просто) - операция AND.
Для него достаточно чтобы учитель вернул класс
package perceptron;
public class Teacher {
public Neuron teach() {
return new AndNeuron();
}
}
А вот и сам класс
package perceptron;
public class AndNeuron implements Neuron {
public double process(double... input) {
return (0.3*input[0] + 0.3*input[1] > 0.5)?1:0;
}
}
Хаха, как смешно. А не смешно! Именно так оно и работает.
А чтобы заработал тест на OR надо подсунуть другую реализацию
package perceptron;
public class OrNeuron implements Neuron {
public double process(double... input) {
return (0.6*input[0] + 0.6*input[1] > 0.5)?1:0;
}
}
Разницу уловили?
А вот для NOT
package perceptron;
public class NotNeuron implements Neuron {
public double process(double... input) {
return (0.6*input[0] + -0.09999999999999998*input[1] > 0.5)?1:0;
}
}
И что получается. Всего две константы говорят нам какая операция будет на выходе? Ага, именно.
Теперь нам осталось сделать такую реализацию, которая в зависимости от входных условий (того самого экземпляра Patterns) могла сама находить необходимые константы.
Самый простой вывод - его величество Random. Попробуем!
Кстати учитель немного поменялся - теперь он хоть чем-то (перебором) занимается.
package perceptron;
public class RandomTeacher {
private Patterns patterns;
public Teacher(Patterns patterns) {
this.patterns = patterns;
}
public Neuron teach() {
Neuron neuron;
do {
neuron = new RandomNeuron();
} while (!match(patterns, neuron));
return neuron;
}
private boolean match(Patterns patterns, Neuron neuron) {
for (InOut inOut : patterns) {
double expected = inOut.getOut();
double actual = neuron.process(inOut.getIn()[0], inOut.getIn()[1]);
if (expected != actual) {
return false;
}
}
return true;
}
}
Я назвал класс RandomTeacher потому как планирую его оставить в коде (OCP).
Я бы тут добавил условие на dead loop, но не хотелось в примере усложнять код.
Тут же наверное стоит привести все остальные классы: Pattern, InOut и In. Родились они вокруг массива double - я просто не люблю массивы, у них интерфейс не как у всех объектов.
package perceptron;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class Patterns implements Iterable<InOut> {
private List<InOut> inOuts;
public Patterns(double[][] data) {
int countPatterns = data.length;
int countInput = data[0].length - 1;
inOuts = new LinkedList<InOut>();
for (int index = 0; index < countPatterns; index ++) {
double[] in = Arrays.copyOf(data[index], data[index].length - 1);
inOuts.add(new InOut(in, data[index][countInput]));
}
}
public InOut get(int index) {
return inOuts.get(index).copy();
}
public Iterator<InOut> iterator() {
return new LinkedList(inOuts).iterator();
}
public int getInCount() {
return get(0).getIn().length;
}
}
package perceptron;
public class InOut {
private In input;
private double output;
public InOut(double[] input, double output) {
this.input = new In(input);
this.output = output;
}
InOut(InOut inOut) {
this(inOut.getIn(), inOut.getOut());
}
public double[] getIn() {
return input.getAll();
}
public double getOut() {
return this.output;
}
public InOut copy() {
return new InOut(this);
}
}
package perceptron;
import java.util.Arrays;
public class In {
private double[] data;
public In(double[] input) {
data = Arrays.copyOf(input, input.length);
}
public double[] getAll() {
return Arrays.copyOf(data, data.length);
}
public double get(int index) {
return data[index];
}
}
Короче, вопрос, почему они такие, а не другие, и почему они вообще есть лучше упустить. Это какая-то 15я версия их, и мы их менять не будем еще долго. Позже я надеюсь от них избавится как-то...
После такой-себе рекламной паузы, направлю нас в сторону решения, которое предложил автор в самом начале.
Синапсы, как мы уже их назвали, можно изменять походу дела (обучения). Делать это будет учитель. И делать он это будет как раньше в школах делали - указкой по пальцам, если что-то не так.
Учителю дадим такую возможность через метод correct у нейрона.
Код все тот же, только вынес константы и добавил метод correct.
Теперь нарисуем этого учителя-злюку!
package perceptron;
public class Teacher {
private Patterns patterns;
private Neuron neuron;
private double allError;
public Teacher(Patterns patterns) {
this.patterns = patterns;
this.neuron = new TwoInputNeuron();
allError = 0;
}
public Neuron teach() {
do {
allError = 0;
for (InOut inOut : patterns) {
teach(inOut);
}
} while (allError != 0);
return neuron;
}
private void teach(InOut inOut) {
double result = neuron.process(inOut.getIn());
double error = inOut.getOut() - result;
neuron.correct(error);
allError = allError + Math.abs(error);
}
}
А теперь перейдем к тесту XOR
package perceptron;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.fail;
public class XorNeuronTest {
private Patterns xorPattern = new Patterns(new double[][]{
{0, 0, 0},
{0, 1, 1},
{1, 0, 1},
{1, 1, 0},
});
@Test
public void shouldExceptionWhenTeach(){
Teacher teacher = new Teacher(xorPattern);
try {
Neuron neuron = teacher.teach();
fail("Ожидается исключение");
} catch(RuntimeException exception) {
assertEquals("Простите, но прецептрон туп и необучаем!",
exception.getMessage());
}
}
}
Он такой специально. Потому как его никак не решить такому простому нейрончику аж никак. Нет таких констант-синапсов, которые при суммировании на них входных сигналов дадут соотвествующие выходные сигналы.
Ну и в тесте мы ожидаем исключение, а потому учитель чуть переписался и стал (SecuredTeacher)
package perceptron;
import java.util.Arrays;
public class SingleNeuron implements Neuron {
private static double DELTA = 0.5;
private static double INIT_SYNAPSE = 0.5;
private static double SYNAPSE_CERRECTION = 0.1;
private static double HOT = 1.0;
private static double COLD = 0.0;
private double[] enters;
private double outer;
private double[] synapses;
public SingleNeuron(int countIn) {
initWeight(countIn);
}
public double process(double... input) {
enters = Arrays.copyOf(input, input.length);
outer = COLD;
for (int index = 0; index < enters.length; index ++) {
outer = outer + enters[index]* synapses[index];
}
if (outer > DELTA) {
outer = HOT;
} else {
outer = COLD;
}
return outer;
}
private void initWeight(int countIn) {
synapses = new double[countIn];
for (int index = 0; index < countIn; index ++) {
synapses[index] = INIT_SYNAPSE;
}
}
public void correct(double error) {
for (int index = 0; index < enters.length; index ++) {
synapses[index] += SYNAPSE_CERRECTION*error*enters[index];
}
}
}
А нейрон я сделал мультивходовым
package perceptron;
import java.util.Arrays;
public class SingleNeuron implements Neuron {
private static double DELTA = 0.5;
private static double INIT_SYNAPSE = 0.5;
private static double SYNAPSE_CERRECTION = 0.1;
private static double HOT = 1.0;
private static double COLD = 0.0;
private double[] enters;
private double outer;
private double[] synapses;
public SingleNeuron(int countIn) {
initWeight(countIn);
}
public double process(double... input) {
enters = Arrays.copyOf(input, input.length);
outer = COLD;
for (int index = 0; index < enters.length; index ++) {
outer = outer + enters[index]* synapses[index];
}
if (outer > DELTA) {
outer = HOT;
} else {
outer = COLD;
}
return outer;
}
private void initWeight(int countIn) {
synapses = new double[countIn];
for (int index = 0; index < countIn; index ++) {
synapses[index] = INIT_SYNAPSE;
}
}
public void correct(double error) {
for (int index = 0; index < enters.length; index ++) {
synapses[index] += SYNAPSE_CERRECTION*error*enters[index];
}
}
}
Но нет ничего неразрешимого. Мы можем построить несколько слоев нейронов и работая с ними подобным образом (синапсы-опыт, учитель, линейка, коррекция опыта) настроить синапсы так, чтобы на любой вход выдавался любой желаемый выход.
Время от времени я пробую делать полный halt. На самом пике актива я хочу останавливаться и медитировать. Я хочу себе это в привычку взять. Я уже это делаю и буду делать больше.
Медитация, это инструмент, который поможет решить любой вопрос. Больше не надо ничему учиться. Мне стоит просто на время заткнуть внешнюю и внутреннюю болталку и помолчать. Просто помолчать. Ответ будет. Ибо, если вопрос вызрел - ответ поспеет. Ученик готов - учитель найдется. Идея в том, что я сам и ученик и учитель.
Во время спарринга ученик никак не может побороть своего более опытного соперника. Он применил все известные ему уловки, но каждая из них была сразу встречена контрприемом. По окончании схватки, расстроенный неудачей, он пришел к своему учителю за советом. Учитель, заметив его мрачное состояние, провел на полу мелом линию длиною около двух метров.
"Как можно сделать эту линию короче?" - спросил он. Ученик изучил линию и сделал несколько предложений, включая предложение разбить линию на несколько кусков. Учитель покачал головой и начертил вторую линию, более длинную, чем первая.
"Как теперь выглядит первая линия?"
"Более короткой", - ответил студент.
Учитель кивнул в знак согласия: "Всегда лучше удлинить свою линию - то есть поднять свое искусство, чем пытаться урезать линию своего противника".
В этом блоге я делюсь своим опытом. Не стоит пробовать ничего из того, что тут описано - это может быть вредно для вас или окружающих вас людей. Ответственность за применение любой из идей, описанных в блоге - всецело лежит на читателе.
Перед тем, как продолжать читать этот блог внимательно прочтите это сообщение.
Email рассылка
Нравится статья?
Как найти статью в блоге?
Я юзаю для этого google, в который я ввожу два слова "а пофиг" и что-то из того, что ищу - так быстрее. Пример