Poetic Fantasy of van Gogh’s Journey

Mxzhan
7 min readJan 20, 2024

--

Description — These two short poems capture Vincent van Gogh’s creative journey, reflecting his passion, inspiration, talent, desire, and struggles with mental health.

Reflection — Creating computational poetry with AI, particularly using a technology like Word2Vec, has been an intriguing journey for me. It’s like blending two distinct worlds: the structured, rule-based realm of coding and the unrestricted, imaginative domain of poetry. In this process, I see poetry as a lush, untamed garden, and coding as the act of carving a path through it.

When I started adopting Word2Vec, my feelings were a mix of excitement and nervousness. I was thrilled by the prospect of seeing poetry emerge in such a natural and fluid way through AI. Word2Vec opened up new linguistic pathways and connections, offering insights that were not immediately evident to me. It felt like having a skilled guide unveiling hidden links within the words, enriching my poetic landscape beyond my usual boundaries.

However, this venture into AI-driven poetry also brought me a sense of worry. As a human being deeply invested in the value of personal creativity and intelligence, I couldn’t help but wonder about the implications of AI in the realm of human artistry. The rapid learning and adaptive capabilities of AI made me question if human creativity could one day be overshadowed or even replaced by such technology.

Yet, as I delved deeper, I realized that AI in poetry is more of a collaborator than a replacement — we share certain of co-authorship. It enhances and extends my creative process rather than supplanting it. The emotional depth, personal experiences, and subjective nuances that I bring as a human are aspects that AI cannot replicate. They form the core of my artistic expression, irreplaceable and unique.

Besides, an interesting observation I’ve made while working with ChatGPT: I usually address it as ‘Hi, GPT, please give me…’ This behavior reveals that deep down, I already perceive AI tools as having an equal status to mine — they are not my subordinates, nor am I theirs. We are collaborators. Addressing ChatGPT directly and respectfully shows that I acknowledge its potential to meaningfully contribute to my tasks. It signifies my recognition of AI’s sophistication, not merely executing commands but engaging in a form of dialogue and collaboration. This interaction style, which somewhat humanizes the AI, positions it more as a peer in my creative endeavors.

My experience also underscores an important aspect of the human-AI relationship. It suggests the potential for AI to work alongside humans, complementing our skills and contributing to our projects in previously unattainable ways. It’s a partnership where human creativity, intuition, and emotion are augmented by AI’s processing power, data-handling, and pattern recognition capabilities.

“van Gogh feels” code

// random seed (if set, sequence can be reproduce)

// Math.srandom( 515 );

// instantiate

Word2Vec model;

// pre-trained model to load

me.dir() + “glove-wiki-gigaword-50-tsne-2.txt” => string filepath;

// load pre-trained model (see URLs above for download)

if( !model.load( filepath ) )

{

<<< “cannot load model:”, filepath >>>;

me.exit();

}

// starter “van Gogh” emotion words with positive connotations

[“innovated”, “transformed”, “revolutionized”, “inspired”, “envisioned”,

“pioneered”, “created”, “experimented”, “challenged”, “mastered”,

“playful”, “explored” ] @=> string positives[];

// starter “van Gogh” emotion words with negative connotations

[“distorted”, “bored”, “overwhelmed”, “crushed”, “worried”,

“afraid”, “defied”, “misunderstood”, “powerless”,

“obsessed”, “isolated”, “guilt”, “cringe”, “dead” ] @=> string negatives[];

// starter “van Gogho” emotion words with other connotations

[“numb”, “nothing”, “weird”, “meh”, “disjointed”, “scattered”,

“complicated”, “sus” ] @=> string others[];

// conditions

3 => int LINES_PER_STANZA;

3 => int NUM_SECTIONS; // here each section is a fixed stanzas format

// number of nearest words to retrieve for each word

// higher this number the higher the variance per word

10 => int K_NEAREST;

// timing

400::ms => dur T_WORD; // duration per word

false => int shouldScaleTimeToWordLength; // longer words take longer?

T_WORD => dur T_LINE_PAUSE; // a little pause after each line

T_WORD * 2 => dur T_STANZA_PAUSE; // pause after each stanza

// sound

Moog crystal => Gain left => dac.left;

crystal => Gain right => dac.right;

4 => crystal.freq;

// feedback delay for echos

left => DelayL DL => left; .5 => DL.gain; T_WORD*1.5 => DL.max => DL.delay;

right => DelayL DR => right; .3 => DR.gain; T_WORD*2 => DR.max => DR.delay;

// current word

string van_Gogh;

// word vector

float vec[model.dim()];

// search results

string words[K_NEAREST];

// line break

chout <= IO.newline(); chout.flush();

// loop over stanzas

for( int s; s < NUM_SECTIONS; s++ )

{

// grab a word out of the “good” bag

positives[Math.random2(0,positives.size()-1)] => van_Gogh;

// print a stanza

stanza( van_Gogh, LINES_PER_STANZA, 48, 64 );

// grab a word out of the “bad” bag

negatives[Math.random2(0,negatives.size()-1)] => van_Gogh;

// print a stanza

stanza( van_Gogh, LINES_PER_STANZA, 48, 63 );

// grab a word out of the “other” bag

others[Math.random2(0,others.size()-1)] => van_Gogh;

// print a stanza

stanza( van_Gogh, LINES_PER_STANZA, 36, Math.random2(33,36)*2 );

endStanza();

chout <= IO.newline() <= IO.newline(); chout.flush();

// pause at end of line

T_STANZA_PAUSE => now;

}

// print at the end

chout <= “\”van Gogh\”” <= IO.newline();

chout <= “ — the wild imagination of an artist” <= IO.newline();

chout.flush();

// print a stanza from a starter feeling word

fun void stanza( string van_Gogh, int numLines, int pitch1, int pitch2 )

{

// loop over lines in a stanza

for( int n; n < numLines; n++ )

{

// a line

say(“van Gogh”); play(pitch1); wait();

say(“feels”); wait();

say(van_Gogh); play(pitch2); wait();

endl(); wait();

// get similar words

model.getSimilar( van_Gogh, words.size(), words );

// choose one at random

words[Math.random2(0,words.size()-1)] => van_Gogh;

}

// next line!

chout <= IO.newline(); chout.flush();

// pause at end of line

T_LINE_PAUSE => now;

}

fun void endStanza()

{

// stanza break; no new sound for now

say(“he”); wait();

say(“finished”); wait();

say(“one”); wait();

say(“piece”); wait();

say(“of”); wait();

say(“painting”); wait();

say(“…”); wait();

say(“he”); wait();

say(“cut”); wait();

say(“off”); wait();

say(“his”); wait();

say(“ear”); wait();

say(“…”); wait();

}

// say a word with space after

fun void say( string word )

{

say( word, “ “ );

}

// say a word

fun void say( string word, string append )

{

// print it

chout <= word <= append; chout.flush();

}

// sonify

fun void play( int pitch )

{

play( pitch, Math.random2f(5,8) );

}

// sonify

fun void play( int pitch, float velocity )

{

// convert pitch to frequency and set it

pitch => Std.mtof => crystal.freq;

// note on

velocity => crystal.noteOn;

}

// wait

fun void wait()

{

wait( T_WORD );

}

// wait

fun void wait( dur T )

{

// let time pass, let sound…sound

T => now;

}

// new line with timing

fun void endl()

{

endl( T_WORD );

}

// new line with timing

fun void endl( dur T )

{

// new line

chout <= IO.newline(); chout.flush();

// let time pass

T => now;

}

“Craziness” Code

// default starting word

“craziness” => string STARTING_WORD;

// check arguments, set new starting word if present

if( me.args() > 0 ) me.arg(0) => STARTING_WORD;

// random seed (if set, sequence can be reproduce)

// Math.srandom( 515 );

// instantiate

Word2Vec model;

// pre-trained model to load

me.dir() + “glove-wiki-gigaword-50-tsne-2.txt” => string filepath;

// load a pre-trained model (see URLs above for download)

// this could take a few seconds, depending on model size

if( !model.load( filepath ) )

{

<<< “cannot load model:”, filepath >>>;

me.exit();

}

// conditions

4 => int WORDS_PER_LINE;

4 => int LINES_PER_STANZA;

4 => int NUM_STANZAS;

// number of nearest words to retrieve for each word

// higher this number the higher the variance per word

150 => int K_NEAREST;

// timing

800::ms => dur T_WORD; // duration per word

false => int shouldScaleTimeToWordLength; // longer words take longer?

900::ms => dur T_LINE_PAUSE; // a little pause after each line

3000::ms => dur T_STANZA_PAUSE; // pause after each stanza

// ranges for each dimension (for sound mapping)

float mins[0], maxs[0];

// get bounds for each dimension

model.minMax( mins, maxs );

// sound

ModalBar bar => NRev reverb => dac;

// reverb wet/dry mix

Math.random2(0, 100) => reverb.mix;

// which preset

Math.random2(0, 80) => bar.preset;

// current word

STARTING_WORD => string word;

// word vector

float vec[model.dim()];

// similarity search results from word2vec

string words[K_NEAREST];

// used for scaling up word timing to word length

dur addTime;

// line break

chout <= IO.newline(); chout.flush();

// loop over stanzas

for( int s; s < NUM_STANZAS; s++ )

{

// loop over lines in a stanza

for( int n; n < LINES_PER_STANZA; n++ )

{

// loop over words

for( int w; w < WORDS_PER_LINE; w++ )

{

// print the word, with a space

chout <= word <= “ “; chout.flush();

// get word vector (for sonification)

model.getVector( word, vec );

// sonify from word vector (see mapping possibilities of ModalBar)

// https://chuck.stanford.edu/doc/program/ugen_full.html#ModalBar

// feel free to experiement with what parameters to control with the vector

Math.remap( vec[0], mins[0], maxs[0], 24, 104 ) => Std.mtof => bar.freq;

// use pow to expand/compress the dimensions to affect mapping sensitivity

Math.pow(Math.remap( vec[1], mins[1], maxs[1],0,1), 3.1) => bar.stickHardness;

// ding!

Math.random2f(.5,1) => bar.noteOn;

// if scale time with word length

if( shouldScaleTimeToWordLength )

word.length() * T_WORD/20 => addTime;

// let time pass, let sound…sound

T_WORD + addTime => now;

// get similar words

model.getSimilar( word, words.size(), words );

// choose one at random

words[Math.random2(0,words.size()-1)] => word;

}

// next line!

chout <= IO.newline(); chout.flush();

// pause at end of line

T_LINE_PAUSE => now;

}

// stanza break!

chout <= IO.newline(); chout.flush();

// pause at end of line

T_STANZA_PAUSE => now;

}

// print at the end

chout <= “\”Craziness\”” <= IO.newline();

chout <= “ — a stream of unconsciousness poem” <= IO.newline();

chout.flush();

--

--