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();